From 21491a6efd5fdf8002264b5882e7edec81844358 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 14:44:08 +0000 Subject: [PATCH 1/5] Update coverage data --- README.md | 66 + badge.svg | 1 + data.json | 1 + endpoint.json | 1 + htmlcov/class_index.html | 596 +++++++ htmlcov/coverage_html_cb_6fb7b396.js | 733 ++++++++ htmlcov/favicon_32_cb_58284776.png | Bin 0 -> 1732 bytes htmlcov/function_index.html | 1556 +++++++++++++++++ htmlcov/index.html | 300 ++++ htmlcov/keybd_closed_cb_ce680311.png | Bin 0 -> 9004 bytes htmlcov/status.json | 1 + htmlcov/style_cb_81f8c14c.css | 337 ++++ htmlcov/z_055061514423972c___init___py.html | 118 ++ htmlcov/z_055061514423972c___main___py.html | 105 ++ htmlcov/z_055061514423972c_posteriors_py.html | 239 +++ .../z_055061514423972c_prevalences_py.html | 330 ++++ htmlcov/z_055061514423972c_priors_py.html | 208 +++ htmlcov/z_055061514423972c_risks_py.html | 237 +++ htmlcov/z_055061514423972c_utils_py.html | 373 ++++ htmlcov/z_5bf5c588c698c6cc___init___py.html | 172 ++ htmlcov/z_5bf5c588c698c6cc___main___py.html | 103 ++ htmlcov/z_5bf5c588c698c6cc__version_py.html | 118 ++ htmlcov/z_5bf5c588c698c6cc_cli_py.html | 187 ++ htmlcov/z_5bf5c588c698c6cc_configs_py.html | 847 +++++++++ htmlcov/z_5bf5c588c698c6cc_decorators_py.html | 185 ++ htmlcov/z_5bf5c588c698c6cc_evaluate_py.html | 309 ++++ htmlcov/z_5bf5c588c698c6cc_plots_py.html | 508 ++++++ htmlcov/z_5bf5c588c698c6cc_sample_py.html | 518 ++++++ htmlcov/z_5bf5c588c698c6cc_schedule_py.html | 182 ++ htmlcov/z_5bf5c588c698c6cc_schema_py.html | 162 ++ htmlcov/z_5bf5c588c698c6cc_utils_py.html | 296 ++++ htmlcov/z_9b7bcb970ba14d6a___init___py.html | 140 ++ htmlcov/z_9b7bcb970ba14d6a___main___py.html | 133 ++ htmlcov/z_9b7bcb970ba14d6a_enhance_py.html | 160 ++ htmlcov/z_9b7bcb970ba14d6a_filter_py.html | 196 +++ htmlcov/z_9b7bcb970ba14d6a_generate_py.html | 193 ++ htmlcov/z_9b7bcb970ba14d6a_join_py.html | 174 ++ htmlcov/z_9b7bcb970ba14d6a_lyproxify_py.html | 436 +++++ htmlcov/z_9b7bcb970ba14d6a_split_py.html | 170 ++ htmlcov/z_9b7bcb970ba14d6a_utils_py.html | 113 ++ 40 files changed, 10504 insertions(+) create mode 100644 README.md create mode 100644 badge.svg create mode 100644 data.json create mode 100644 endpoint.json create mode 100644 htmlcov/class_index.html create mode 100644 htmlcov/coverage_html_cb_6fb7b396.js create mode 100644 htmlcov/favicon_32_cb_58284776.png create mode 100644 htmlcov/function_index.html create mode 100644 htmlcov/index.html create mode 100644 htmlcov/keybd_closed_cb_ce680311.png create mode 100644 htmlcov/status.json create mode 100644 htmlcov/style_cb_81f8c14c.css create mode 100644 htmlcov/z_055061514423972c___init___py.html create mode 100644 htmlcov/z_055061514423972c___main___py.html create mode 100644 htmlcov/z_055061514423972c_posteriors_py.html create mode 100644 htmlcov/z_055061514423972c_prevalences_py.html create mode 100644 htmlcov/z_055061514423972c_priors_py.html create mode 100644 htmlcov/z_055061514423972c_risks_py.html create mode 100644 htmlcov/z_055061514423972c_utils_py.html create mode 100644 htmlcov/z_5bf5c588c698c6cc___init___py.html create mode 100644 htmlcov/z_5bf5c588c698c6cc___main___py.html create mode 100644 htmlcov/z_5bf5c588c698c6cc__version_py.html create mode 100644 htmlcov/z_5bf5c588c698c6cc_cli_py.html create mode 100644 htmlcov/z_5bf5c588c698c6cc_configs_py.html create mode 100644 htmlcov/z_5bf5c588c698c6cc_decorators_py.html create mode 100644 htmlcov/z_5bf5c588c698c6cc_evaluate_py.html create mode 100644 htmlcov/z_5bf5c588c698c6cc_plots_py.html create mode 100644 htmlcov/z_5bf5c588c698c6cc_sample_py.html create mode 100644 htmlcov/z_5bf5c588c698c6cc_schedule_py.html create mode 100644 htmlcov/z_5bf5c588c698c6cc_schema_py.html create mode 100644 htmlcov/z_5bf5c588c698c6cc_utils_py.html create mode 100644 htmlcov/z_9b7bcb970ba14d6a___init___py.html create mode 100644 htmlcov/z_9b7bcb970ba14d6a___main___py.html create mode 100644 htmlcov/z_9b7bcb970ba14d6a_enhance_py.html create mode 100644 htmlcov/z_9b7bcb970ba14d6a_filter_py.html create mode 100644 htmlcov/z_9b7bcb970ba14d6a_generate_py.html create mode 100644 htmlcov/z_9b7bcb970ba14d6a_join_py.html create mode 100644 htmlcov/z_9b7bcb970ba14d6a_lyproxify_py.html create mode 100644 htmlcov/z_9b7bcb970ba14d6a_split_py.html create mode 100644 htmlcov/z_9b7bcb970ba14d6a_utils_py.html diff --git a/README.md b/README.md new file mode 100644 index 0000000..12a1fb9 --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +# Repository Coverage + +[Full report](https://htmlpreview.github.io/?https://github.com/lycosystem/lyscripts/blob/python-coverage-comment-action-data/htmlcov/index.html) + +| Name | Stmts | Miss | Cover | Missing | +|-------------------------------------- | -------: | -------: | ------: | --------: | +| src/lyscripts/\_\_init\_\_.py | 34 | 7 | 79% |57-58, 66-72 | +| src/lyscripts/\_\_main\_\_.py | 3 | 3 | 0% | 3-6 | +| src/lyscripts/\_version.py | 13 | 3 | 77% | 8-11 | +| src/lyscripts/cli.py | 26 | 12 | 54% |61-67, 81-86 | +| src/lyscripts/compute/\_\_init\_\_.py | 9 | 1 | 89% | 21 | +| src/lyscripts/compute/\_\_main\_\_.py | 5 | 5 | 0% | 3-8 | +| src/lyscripts/compute/posteriors.py | 46 | 19 | 59% |97-137, 141-142 | +| src/lyscripts/compute/prevalences.py | 80 | 7 | 91% |58-60, 94-99, 232-233 | +| src/lyscripts/compute/priors.py | 35 | 2 | 94% | 110-111 | +| src/lyscripts/compute/risks.py | 51 | 33 | 35% |47-65, 81-135, 139-140 | +| src/lyscripts/compute/utils.py | 120 | 6 | 95% |95, 146, 177, 188, 240, 250 | +| src/lyscripts/configs.py | 255 | 27 | 89% |90, 122, 165, 173, 217, 271, 277-278, 286, 472, 506-509, 514, 585, 624-637, 680 | +| src/lyscripts/data/\_\_init\_\_.py | 12 | 1 | 92% | 43 | +| src/lyscripts/data/\_\_main\_\_.py | 18 | 18 | 0% | 3-36 | +| src/lyscripts/data/enhance.py | 24 | 8 | 67% |39-58, 62-63 | +| src/lyscripts/data/filter.py | 49 | 30 | 39% |43-66, 76-94, 98-99 | +| src/lyscripts/data/generate.py | 39 | 4 | 90% |58, 63, 95-96 | +| src/lyscripts/data/join.py | 20 | 9 | 55% |59-72, 76-77 | +| src/lyscripts/data/lyproxify.py | 121 | 67 | 45% |29-32, 37-44, 88-117, 130-140, 171, 248-280, 291-305, 338-339 | +| src/lyscripts/data/split.py | 30 | 14 | 53% |33-65, 72-73 | +| src/lyscripts/data/utils.py | 9 | 0 | 100% | | +| src/lyscripts/decorators.py | 41 | 4 | 90% | 53-55, 70 | +| src/lyscripts/evaluate.py | 75 | 57 | 24% |29-35, 43-70, 87, 104-109, 120-141, 146-204, 208-212 | +| src/lyscripts/plots.py | 166 | 23 | 86% |26-27, 46-47, 56, 94, 99, 104, 185-186, 336, 341, 370-392, 399 | +| src/lyscripts/sample.py | 136 | 11 | 92% |35-36, 74, 132, 172, 188, 301, 309, 313, 420-421 | +| src/lyscripts/schedule.py | 29 | 13 | 55% |25-27, 35, 44-45, 73-80, 84-85 | +| src/lyscripts/schema.py | 21 | 3 | 86% | 60-61, 65 | +| src/lyscripts/utils.py | 84 | 5 | 94% |25, 141-142, 196-197 | +| **TOTAL** | **1551** | **392** | **75%** | | + + +## Setup coverage badge + +Below are examples of the badges you can use in your main branch `README` file. + +### Direct image + +[![Coverage badge](https://raw.githubusercontent.com/lycosystem/lyscripts/python-coverage-comment-action-data/badge.svg)](https://htmlpreview.github.io/?https://github.com/lycosystem/lyscripts/blob/python-coverage-comment-action-data/htmlcov/index.html) + +This is the one to use if your repository is private or if you don't want to customize anything. + +### [Shields.io](https://shields.io) Json Endpoint + +[![Coverage badge](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/lycosystem/lyscripts/python-coverage-comment-action-data/endpoint.json)](https://htmlpreview.github.io/?https://github.com/lycosystem/lyscripts/blob/python-coverage-comment-action-data/htmlcov/index.html) + +Using this one will allow you to [customize](https://shields.io/endpoint) the look of your badge. +It won't work with private repositories. It won't be refreshed more than once per five minutes. + +### [Shields.io](https://shields.io) Dynamic Badge + +[![Coverage badge](https://img.shields.io/badge/dynamic/json?color=brightgreen&label=coverage&query=%24.message&url=https%3A%2F%2Fraw.githubusercontent.com%2Flycosystem%2Flyscripts%2Fpython-coverage-comment-action-data%2Fendpoint.json)](https://htmlpreview.github.io/?https://github.com/lycosystem/lyscripts/blob/python-coverage-comment-action-data/htmlcov/index.html) + +This one will always be the same color. It won't work for private repos. I'm not even sure why we included it. + +## What is that? + +This branch is part of the +[python-coverage-comment-action](https://github.com/marketplace/actions/python-coverage-comment) +GitHub Action. All the files in this branch are automatically generated and may be +overwritten at any moment. \ No newline at end of file diff --git a/badge.svg b/badge.svg new file mode 100644 index 0000000..993547f --- /dev/null +++ b/badge.svg @@ -0,0 +1 @@ +Coverage: 74%Coverage74% \ No newline at end of file diff --git a/data.json b/data.json new file mode 100644 index 0000000..1ec6703 --- /dev/null +++ b/data.json @@ -0,0 +1 @@ +{"coverage": 74.72598323662153, "raw_data": {"meta": {"format": 3, "version": "7.9.1", "timestamp": "2025-06-26T14:44:06.796026", "branch_coverage": false, "show_contexts": false}, "files": {"src/lyscripts/__init__.py": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 20, 21, 22, 23, 25, 26, 27, 28, 29, 33, 35, 38, 39, 41, 45, 50, 51, 52, 53, 55, 60, 75], "summary": {"covered_lines": 27, "num_statements": 34, "percent_covered": 79.41176470588235, "percent_covered_display": "79", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [57, 58, 66, 68, 69, 70, 72], "excluded_lines": [], "functions": {"LyscriptsCLI.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [57, 58], "excluded_lines": []}, "LyscriptsCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [66, 68, 69, 70, 72], "excluded_lines": []}, "": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 20, 21, 22, 23, 25, 26, 27, 28, 29, 33, 35, 38, 39, 41, 45, 50, 51, 52, 53, 55, 60, 75], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"LyscriptsCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [57, 58, 66, 68, 69, 70, 72], "excluded_lines": []}, "": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 20, 21, 22, 23, 25, 26, 27, 28, 29, 33, 35, 38, 39, 41, 45, 50, 51, 52, 53, 55, 60, 75], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/lyscripts/__main__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [3, 5, 6], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [3, 5, 6], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [3, 5, 6], "excluded_lines": []}}}, "src/lyscripts/_version.py": {"executed_lines": [4, 6, 7, 13, 15, 16, 17, 18, 20, 21], "summary": {"covered_lines": 10, "num_statements": 13, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [8, 9, 11], "excluded_lines": [], "functions": {"": {"executed_lines": [4, 6, 7, 13, 15, 16, 17, 18, 20, 21], "summary": {"covered_lines": 10, "num_statements": 13, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [8, 9, 11], "excluded_lines": []}}, "classes": {"": {"executed_lines": [4, 6, 7, 13, 15, 16, 17, 18, 20, 21], "summary": {"covered_lines": 10, "num_statements": 13, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [8, 9, 11], "excluded_lines": []}}}, "src/lyscripts/cli.py": {"executed_lines": [1, 11, 12, 14, 15, 16, 17, 18, 21, 35, 37, 44, 46, 49, 70], "summary": {"covered_lines": 14, "num_statements": 26, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [61, 62, 63, 64, 65, 67, 81, 82, 83, 84, 85, 86], "excluded_lines": [], "functions": {"assemble_main": {"executed_lines": [35, 46], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "assemble_main.main": {"executed_lines": [37, 44], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "somewhat_safely_get_loglevel": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [61, 62, 63, 64, 65, 67], "excluded_lines": []}, "configure_logging": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [81, 82, 83, 84, 85, 86], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 14, 15, 16, 17, 18, 21, 49, 70], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 11, 12, 14, 15, 16, 17, 18, 21, 35, 37, 44, 46, 49, 70], "summary": {"covered_lines": 14, "num_statements": 26, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [61, 62, 63, 64, 65, 67, 81, 82, 83, 84, 85, 86], "excluded_lines": []}}}, "src/lyscripts/compute/__init__.py": {"executed_lines": [1, 6, 8, 11, 12, 14, 15, 16, 17, 19], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [21], "excluded_lines": [], "functions": {"ComputeCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [21], "excluded_lines": []}, "": {"executed_lines": [1, 6, 8, 11, 12, 14, 15, 16, 17, 19], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ComputeCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [21], "excluded_lines": []}, "": {"executed_lines": [1, 6, 8, 11, 12, 14, 15, 16, 17, 19], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/lyscripts/compute/__main__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [3, 4, 6, 7, 8], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [3, 4, 6, 7, 8], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [3, 4, 6, 7, 8], "excluded_lines": []}}}, "src/lyscripts/compute/posteriors.py": {"executed_lines": [1, 9, 11, 12, 13, 14, 15, 17, 18, 19, 20, 29, 32, 51, 52, 53, 54, 55, 57, 58, 60, 66, 75, 78, 79, 81, 87, 91, 140], "summary": {"covered_lines": 27, "num_statements": 46, "percent_covered": 58.69565217391305, "percent_covered_display": "59", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [97, 99, 102, 104, 105, 106, 107, 109, 110, 111, 113, 122, 123, 125, 135, 136, 137, 141, 142], "excluded_lines": [], "functions": {"compute_posteriors": {"executed_lines": [51, 52, 53, 54, 55, 57, 58, 60, 66, 75], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PosteriorsCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [97, 99, 102, 104, 105, 106, 107, 109, 110, 111, 113, 122, 123, 125, 135, 136, 137], "excluded_lines": []}, "": {"executed_lines": [1, 9, 11, 12, 13, 14, 15, 17, 18, 19, 20, 29, 32, 78, 79, 81, 87, 91, 140], "summary": {"covered_lines": 17, "num_statements": 19, "percent_covered": 89.47368421052632, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [141, 142], "excluded_lines": []}}, "classes": {"PosteriorsCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [97, 99, 102, 104, 105, 106, 107, 109, 110, 111, 113, 122, 123, 125, 135, 136, 137], "excluded_lines": []}, "": {"executed_lines": [1, 9, 11, 12, 13, 14, 15, 17, 18, 19, 20, 29, 32, 51, 52, 53, 54, 55, 57, 58, 60, 66, 75, 78, 79, 81, 87, 91, 140], "summary": {"covered_lines": 27, "num_statements": 29, "percent_covered": 93.10344827586206, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [141, 142], "excluded_lines": []}}}, "src/lyscripts/compute/prevalences.py": {"executed_lines": [1, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 28, 40, 43, 54, 55, 57, 62, 63, 64, 66, 72, 73, 78, 79, 81, 87, 101, 103, 106, 108, 109, 110, 111, 112, 113, 114, 117, 141, 142, 144, 145, 146, 148, 155, 161, 162, 164, 170, 173, 175, 177, 178, 181, 183, 184, 185, 186, 188, 189, 190, 192, 201, 202, 204, 214, 219, 220, 221, 222, 231], "summary": {"covered_lines": 73, "num_statements": 80, "percent_covered": 91.25, "percent_covered_display": "91", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [58, 59, 60, 94, 99, 232, 233], "excluded_lines": [], "functions": {"compute_prevalences": {"executed_lines": [54, 55, 57, 62, 63, 64, 66, 72, 73, 78, 79, 81, 87, 101, 103], "summary": {"covered_lines": 15, "num_statements": 20, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [58, 59, 60, 94, 99], "excluded_lines": []}, "generate_query_from_diagnosis": {"executed_lines": [108, 109, 110, 111, 112, 113, 114], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "observe_prevalence": {"executed_lines": [141, 142, 144, 145, 146, 148, 155], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PrevalencesCLI.cli_cmd": {"executed_lines": [177, 178, 181, 183, 184, 185, 186, 188, 189, 190, 192, 201, 202, 204, 214, 219, 220, 221, 222], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 28, 40, 43, 106, 117, 161, 162, 164, 170, 173, 175, 231], "summary": {"covered_lines": 25, "num_statements": 27, "percent_covered": 92.5925925925926, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [232, 233], "excluded_lines": []}}, "classes": {"PrevalencesCLI": {"executed_lines": [177, 178, 181, 183, 184, 185, 186, 188, 189, 190, 192, 201, 202, 204, 214, 219, 220, 221, 222], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 28, 40, 43, 54, 55, 57, 62, 63, 64, 66, 72, 73, 78, 79, 81, 87, 101, 103, 106, 108, 109, 110, 111, 112, 113, 114, 117, 141, 142, 144, 145, 146, 148, 155, 161, 162, 164, 170, 173, 175, 231], "summary": {"covered_lines": 54, "num_statements": 61, "percent_covered": 88.52459016393442, "percent_covered_display": "89", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [58, 59, 60, 94, 99, 232, 233], "excluded_lines": []}}}, "src/lyscripts/compute/priors.py": {"executed_lines": [1, 7, 9, 10, 11, 12, 14, 15, 16, 23, 26, 42, 43, 44, 46, 52, 53, 60, 63, 64, 66, 68, 84, 85, 86, 88, 89, 90, 92, 93, 94, 96, 105, 106, 109], "summary": {"covered_lines": 33, "num_statements": 35, "percent_covered": 94.28571428571429, "percent_covered_display": "94", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [110, 111], "excluded_lines": [], "functions": {"compute_priors": {"executed_lines": [42, 43, 44, 46, 52, 53, 60], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PriorsCLI.cli_cmd": {"executed_lines": [84, 85, 86, 88, 89, 90, 92, 93, 94, 96, 105, 106], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 7, 9, 10, 11, 12, 14, 15, 16, 23, 26, 63, 64, 66, 68, 109], "summary": {"covered_lines": 14, "num_statements": 16, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [110, 111], "excluded_lines": []}}, "classes": {"PriorsCLI": {"executed_lines": [84, 85, 86, 88, 89, 90, 92, 93, 94, 96, 105, 106], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 7, 9, 10, 11, 12, 14, 15, 16, 23, 26, 42, 43, 44, 46, 52, 53, 60, 63, 64, 66, 68, 109], "summary": {"covered_lines": 21, "num_statements": 23, "percent_covered": 91.30434782608695, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [110, 111], "excluded_lines": []}}}, "src/lyscripts/compute/risks.py": {"executed_lines": [1, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 29, 32, 68, 69, 71, 77, 79, 138], "summary": {"covered_lines": 18, "num_statements": 51, "percent_covered": 35.294117647058826, "percent_covered_display": "35", "missing_lines": 33, "excluded_lines": 0}, "missing_lines": [47, 48, 49, 50, 52, 53, 55, 61, 65, 81, 82, 85, 87, 88, 89, 90, 91, 93, 94, 95, 97, 106, 107, 109, 119, 120, 122, 132, 133, 134, 135, 139, 140], "excluded_lines": [], "functions": {"compute_risks": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [47, 48, 49, 50, 52, 53, 55, 61, 65], "excluded_lines": []}, "RisksCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [81, 82, 85, 87, 88, 89, 90, 91, 93, 94, 95, 97, 106, 107, 109, 119, 120, 122, 132, 133, 134, 135], "excluded_lines": []}, "": {"executed_lines": [1, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 29, 32, 68, 69, 71, 77, 79, 138], "summary": {"covered_lines": 18, "num_statements": 20, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [139, 140], "excluded_lines": []}}, "classes": {"RisksCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [81, 82, 85, 87, 88, 89, 90, 91, 93, 94, 95, 97, 106, 107, 109, 119, 120, 122, 132, 133, 134, 135], "excluded_lines": []}, "": {"executed_lines": [1, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 29, 32, 68, 69, 71, 77, 79, 138], "summary": {"covered_lines": 18, "num_statements": 29, "percent_covered": 62.06896551724138, "percent_covered_display": "62", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [47, 48, 49, 50, 52, 53, 55, 61, 65, 139, 140], "excluded_lines": []}}}, "src/lyscripts/compute/utils.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 14, 24, 25, 27, 28, 29, 36, 40, 44, 47, 49, 55, 57, 58, 59, 60, 62, 63, 66, 68, 69, 70, 71, 72, 73, 74, 77, 92, 94, 97, 98, 99, 101, 104, 106, 107, 108, 111, 112, 115, 116, 118, 121, 128, 145, 148, 149, 151, 153, 155, 156, 158, 159, 161, 163, 165, 166, 168, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 187, 189, 191, 194, 210, 211, 212, 213, 214, 215, 216, 217, 219, 222, 239, 242, 243, 244, 246, 247, 248, 249, 252, 254, 257, 259, 260, 261, 263, 264, 265, 266, 267, 269, 271, 272, 273, 275, 276], "summary": {"covered_lines": 114, "num_statements": 120, "percent_covered": 95.0, "percent_covered_display": "95", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [95, 146, 177, 188, 240, 250], "excluded_lines": [], "functions": {"is_hdf5_compatible": {"executed_lines": [49], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "to_hdf5_attrs": {"executed_lines": [57, 58, 59, 60, 62, 63], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "from_hdf5_attrs": {"executed_lines": [68, 69, 70, 71, 72, 73, 74], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "extract_modalities": {"executed_lines": [92, 94, 97, 98, 99, 101], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [95], "excluded_lines": []}, "ensure_parent_dir": {"executed_lines": [106, 107, 108], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "HDF5FileStorage._get_dataset": {"executed_lines": [145, 148, 149], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [146], "excluded_lines": []}, "HDF5FileStorage.load": {"executed_lines": [153, 155, 156, 158, 159], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "HDF5FileStorage.get_attrs": {"executed_lines": [163, 165, 166, 168, 169], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "HDF5FileStorage.save": {"executed_lines": [173, 175, 176, 178, 180], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [177], "excluded_lines": []}, "HDF5FileStorage.set_attrs": {"executed_lines": [184, 186, 187, 189, 191], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [188], "excluded_lines": []}, "reduce_pattern": {"executed_lines": [210, 211, 212, 213, 214, 215, 216, 217, 219], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "complete_pattern": {"executed_lines": [239, 242, 243, 244, 246, 247, 248, 249, 252, 254], "summary": {"covered_lines": 10, "num_statements": 12, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [240, 250], "excluded_lines": []}, "get_cached": {"executed_lines": [259, 260, 261, 263, 264, 275, 276], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_cached.log_cache_info_wrapper": {"executed_lines": [265, 266, 267, 269, 271, 272, 273], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 14, 24, 25, 27, 28, 29, 36, 40, 44, 47, 55, 66, 77, 104, 111, 112, 115, 116, 118, 121, 128, 151, 161, 171, 182, 194, 222, 257], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"BaseComputeCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "HDF5FileStorage": {"executed_lines": [145, 148, 149, 153, 155, 156, 158, 159, 163, 165, 166, 168, 169, 173, 175, 176, 178, 180, 184, 186, 187, 189, 191], "summary": {"covered_lines": 23, "num_statements": 26, "percent_covered": 88.46153846153847, "percent_covered_display": "88", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [146, 177, 188], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 14, 24, 25, 27, 28, 29, 36, 40, 44, 47, 49, 55, 57, 58, 59, 60, 62, 63, 66, 68, 69, 70, 71, 72, 73, 74, 77, 92, 94, 97, 98, 99, 101, 104, 106, 107, 108, 111, 112, 115, 116, 118, 121, 128, 151, 161, 171, 182, 194, 210, 211, 212, 213, 214, 215, 216, 217, 219, 222, 239, 242, 243, 244, 246, 247, 248, 249, 252, 254, 257, 259, 260, 261, 263, 264, 265, 266, 267, 269, 271, 272, 273, 275, 276], "summary": {"covered_lines": 91, "num_statements": 94, "percent_covered": 96.80851063829788, "percent_covered_display": "97", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [95, 240, 250], "excluded_lines": []}}}, "src/lyscripts/configs.py": {"executed_lines": [1, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 39, 44, 46, 48, 51, 56, 57, 59, 63, 69, 70, 72, 78, 82, 87, 89, 92, 94, 96, 102, 104, 107, 108, 110, 115, 120, 128, 129, 131, 135, 139, 145, 146, 148, 153, 159, 161, 162, 164, 167, 168, 170, 171, 176, 177, 179, 182, 186, 187, 189, 190, 202, 204, 205, 206, 208, 209, 211, 214, 216, 219, 220, 222, 225, 226, 228, 232, 236, 240, 244, 253, 258, 259, 261, 270, 273, 275, 276, 280, 281, 282, 283, 285, 288, 296, 298, 299, 306, 307, 316, 321, 325, 332, 336, 341, 343, 348, 349, 350, 355, 357, 359, 360, 362, 363, 364, 366, 367, 368, 370, 372, 379, 380, 381, 387, 390, 391, 393, 396, 400, 404, 412, 416, 420, 424, 431, 435, 439, 443, 451, 457, 464, 466, 467, 469, 470, 475, 476, 478, 482, 487, 491, 495, 496, 498, 500, 501, 503, 505, 511, 513, 519, 521, 522, 523, 524, 525, 526, 529, 550, 551, 553, 554, 555, 561, 562, 565, 572, 573, 574, 576, 578, 579, 580, 581, 582, 583, 587, 588, 589, 590, 592, 594, 595, 598, 604, 605, 606, 608, 609, 610, 612, 613, 616, 640, 643, 644, 657, 672, 673, 675, 677, 678, 679, 684, 686, 688, 692, 693, 699, 701, 703, 713, 714, 716, 718, 728, 729, 738, 743, 744], "summary": {"covered_lines": 228, "num_statements": 255, "percent_covered": 89.41176470588235, "percent_covered_display": "89", "missing_lines": 27, "excluded_lines": 0}, "missing_lines": [90, 122, 165, 173, 217, 271, 277, 278, 286, 472, 506, 507, 509, 514, 585, 624, 625, 627, 628, 629, 631, 632, 633, 635, 636, 637, 680], "excluded_lines": [], "functions": {"DataConfig.load": {"executed_lines": [89, 92], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [90], "excluded_lines": []}, "DataConfig.get_load_kwargs": {"executed_lines": [96], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "check_pattern": {"executed_lines": [104], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DiagnosisConfig.to_involvement": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [122], "excluded_lines": []}, "retrieve_graph_representation": {"executed_lines": [161, 162, 164, 167, 168, 170, 171], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [165, 173], "excluded_lines": []}, "GraphConfig.from_model": {"executed_lines": [189, 190], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "has_model_symbol": {"executed_lines": [204, 205, 206, 208, 209, 211], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_symmetry_kwargs": {"executed_lines": [216, 219, 220, 222], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [217], "excluded_lines": []}, "ModelConfig.from_model": {"executed_lines": [261, 270, 273, 275, 276, 280, 281, 282, 283, 285, 288], "summary": {"covered_lines": 11, "num_statements": 15, "percent_covered": 73.33333333333333, "percent_covered_display": "73", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [271, 277, 278, 286], "excluded_lines": []}, "modalityconfig_from_model": {"executed_lines": [298, 299], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DeprecatedModelConfig.model_post_init": {"executed_lines": [343, 348, 349, 350, 355], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DeprecatedModelConfig.translate": {"executed_lines": [359, 360, 362, 363, 364, 366, 367, 368, 370, 372, 379, 380, 381, 387], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SamplingConfig.load": {"executed_lines": [457], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "map_to_optional_bool": {"executed_lines": [466, 467, 469, 470], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [472], "excluded_lines": []}, "ScenarioConfig.model_post_init": {"executed_lines": [500, 501], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ScenarioConfig.interpolate": {"executed_lines": [505], "summary": {"covered_lines": 1, "num_statements": 4, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [506, 507, 509], "excluded_lines": []}, "ScenarioConfig.normalize": {"executed_lines": [513], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [514], "excluded_lines": []}, "_construct_model_from_external": {"executed_lines": [521, 522, 523, 524, 525, 526], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "construct_model": {"executed_lines": [550, 551, 553, 554, 555, 561, 562], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "add_distributions": {"executed_lines": [572, 573, 574, 576, 578, 579, 580, 581, 582, 583, 587, 588, 589, 590, 592, 594, 595], "summary": {"covered_lines": 17, "num_statements": 18, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [585], "excluded_lines": []}, "add_modalities": {"executed_lines": [604, 605, 606, 608, 609, 610, 612, 613], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "add_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [624, 625, 627, 628, 629, 631, 632, 633, 635, 636, 637], "excluded_lines": []}, "DynamicYamlConfigSettingsSource.__init__": {"executed_lines": [672, 673], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DynamicYamlConfigSettingsSource._read_file": {"executed_lines": [677, 678, 679, 684], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [680], "excluded_lines": []}, "DynamicYamlConfigSettingsSource.__call__": {"executed_lines": [688, 692, 693, 699], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DynamicYamlConfigSettingsSource.__repr__": {"executed_lines": [703], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BaseCLI.settings_customise_sources": {"executed_lines": [738, 743, 744], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 39, 44, 46, 48, 51, 56, 57, 59, 63, 69, 70, 72, 78, 82, 87, 94, 102, 107, 108, 110, 115, 120, 128, 129, 131, 135, 139, 145, 146, 148, 153, 159, 176, 177, 179, 182, 186, 187, 202, 214, 225, 226, 228, 232, 236, 240, 244, 253, 258, 259, 296, 306, 307, 316, 321, 325, 332, 336, 341, 357, 390, 391, 393, 396, 400, 404, 412, 416, 420, 424, 431, 435, 439, 443, 451, 464, 475, 476, 478, 482, 487, 491, 495, 496, 498, 503, 511, 519, 529, 565, 598, 616, 640, 643, 644, 657, 675, 686, 701, 713, 714, 716, 718, 728, 729], "summary": {"covered_lines": 112, "num_statements": 112, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"CrossValidationConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DataConfig": {"executed_lines": [89, 92, 96], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [90], "excluded_lines": []}, "DiagnosisConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [122], "excluded_lines": []}, "DistributionConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "InvolvementConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "GraphConfig": {"executed_lines": [189, 190], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ModelConfig": {"executed_lines": [261, 270, 273, 275, 276, 280, 281, 282, 283, 285, 288], "summary": {"covered_lines": 11, "num_statements": 15, "percent_covered": 73.33333333333333, "percent_covered_display": "73", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [271, 277, 278, 286], "excluded_lines": []}, "DeprecatedModelConfig": {"executed_lines": [343, 348, 349, 350, 355, 359, 360, 362, 363, 364, 366, 367, 368, 370, 372, 379, 380, 381, 387], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SamplingConfig": {"executed_lines": [457], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ScenarioConfig": {"executed_lines": [500, 501, 505, 513], "summary": {"covered_lines": 4, "num_statements": 8, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [506, 507, 509, 514], "excluded_lines": []}, "DynamicYamlConfigSettingsSource": {"executed_lines": [672, 673, 677, 678, 679, 684, 688, 692, 693, 699, 703], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [680], "excluded_lines": []}, "BaseCLI": {"executed_lines": [738, 743, 744], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 39, 44, 46, 48, 51, 56, 57, 59, 63, 69, 70, 72, 78, 82, 87, 94, 102, 104, 107, 108, 110, 115, 120, 128, 129, 131, 135, 139, 145, 146, 148, 153, 159, 161, 162, 164, 167, 168, 170, 171, 176, 177, 179, 182, 186, 187, 202, 204, 205, 206, 208, 209, 211, 214, 216, 219, 220, 222, 225, 226, 228, 232, 236, 240, 244, 253, 258, 259, 296, 298, 299, 306, 307, 316, 321, 325, 332, 336, 341, 357, 390, 391, 393, 396, 400, 404, 412, 416, 420, 424, 431, 435, 439, 443, 451, 464, 466, 467, 469, 470, 475, 476, 478, 482, 487, 491, 495, 496, 498, 503, 511, 519, 521, 522, 523, 524, 525, 526, 529, 550, 551, 553, 554, 555, 561, 562, 565, 572, 573, 574, 576, 578, 579, 580, 581, 582, 583, 587, 588, 589, 590, 592, 594, 595, 598, 604, 605, 606, 608, 609, 610, 612, 613, 616, 640, 643, 644, 657, 675, 686, 701, 713, 714, 716, 718, 728, 729], "summary": {"covered_lines": 174, "num_statements": 190, "percent_covered": 91.57894736842105, "percent_covered_display": "92", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [165, 173, 217, 472, 585, 624, 625, 627, 628, 629, 631, 632, 633, 635, 636, 637], "excluded_lines": []}}}, "src/lyscripts/data/__init__.py": {"executed_lines": [1, 17, 19, 28, 31, 32, 34, 35, 36, 37, 38, 39, 41], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [43], "excluded_lines": [], "functions": {"DataCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [43], "excluded_lines": []}, "": {"executed_lines": [1, 17, 19, 28, 31, 32, 34, 35, 36, 37, 38, 39, 41], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DataCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [43], "excluded_lines": []}, "": {"executed_lines": [1, 17, 19, 28, 31, 32, 34, 35, 36, 37, 38, 39, 41], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/lyscripts/data/__main__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 7, 10, 13, 15, 20, 21, 25, 26, 27, 28, 29, 31, 32, 35, 36], "excluded_lines": [], "functions": {"main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [15, 20, 21, 25, 26, 27, 28, 29, 31, 32], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 7, 10, 13, 35, 36], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 7, 10, 13, 15, 20, 21, 25, 26, 27, 28, 29, 31, 32, 35, 36], "excluded_lines": []}}}, "src/lyscripts/data/enhance.py": {"executed_lines": [1, 7, 9, 10, 11, 13, 14, 15, 18, 19, 21, 22, 23, 24, 25, 30, 32, 61], "summary": {"covered_lines": 16, "num_statements": 24, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [39, 41, 42, 44, 49, 58, 62, 63], "excluded_lines": [], "functions": {"EnhanceCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [39, 41, 42, 44, 49, 58], "excluded_lines": []}, "": {"executed_lines": [1, 7, 9, 10, 11, 13, 14, 15, 18, 19, 21, 22, 23, 24, 25, 30, 32, 61], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [62, 63], "excluded_lines": []}}, "classes": {"EnhanceCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [39, 41, 42, 44, 49, 58], "excluded_lines": []}, "": {"executed_lines": [1, 7, 9, 10, 11, 13, 14, 15, 18, 19, 21, 22, 23, 24, 25, 30, 32, 61], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [62, 63], "excluded_lines": []}}}, "src/lyscripts/data/filter.py": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 15, 16, 17, 20, 21, 23, 24, 28, 35, 38, 39, 41, 68, 97], "summary": {"covered_lines": 19, "num_statements": 49, "percent_covered": 38.775510204081634, "percent_covered_display": "39", "missing_lines": 30, "excluded_lines": 0}, "missing_lines": [43, 44, 45, 46, 47, 49, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 66, 76, 78, 79, 84, 85, 87, 88, 89, 91, 92, 94, 98, 99], "excluded_lines": [], "functions": {"FilterCLI.model_post_init": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [43, 44, 45, 46, 47, 49, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 66], "excluded_lines": []}, "FilterCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [76, 78, 79, 84, 85, 87, 88, 89, 91, 92, 94], "excluded_lines": []}, "": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 15, 16, 17, 20, 21, 23, 24, 28, 35, 38, 39, 41, 68, 97], "summary": {"covered_lines": 19, "num_statements": 21, "percent_covered": 90.47619047619048, "percent_covered_display": "90", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [98, 99], "excluded_lines": []}}, "classes": {"FilterCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 28, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [43, 44, 45, 46, 47, 49, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 66, 76, 78, 79, 84, 85, 87, 88, 89, 91, 92, 94], "excluded_lines": []}, "": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 15, 16, 17, 20, 21, 23, 24, 28, 35, 38, 39, 41, 68, 97], "summary": {"covered_lines": 19, "num_statements": 21, "percent_covered": 90.47619047619048, "percent_covered_display": "90", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [98, 99], "excluded_lines": []}}}, "src/lyscripts/data/generate.py": {"executed_lines": [1, 11, 12, 13, 14, 16, 17, 26, 29, 30, 32, 33, 34, 41, 47, 48, 49, 50, 51, 53, 55, 56, 57, 60, 62, 65, 67, 76, 78, 79, 80, 81, 82, 84, 89, 91, 94], "summary": {"covered_lines": 35, "num_statements": 39, "percent_covered": 89.74358974358974, "percent_covered_display": "90", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [58, 63, 95, 96], "excluded_lines": [], "functions": {"GenerateCLI.model_post_init": {"executed_lines": [55, 56, 57, 60, 62, 65], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [58, 63], "excluded_lines": []}, "GenerateCLI.cli_cmd": {"executed_lines": [76, 78, 79, 80, 81, 82, 84, 89, 91], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 13, 14, 16, 17, 26, 29, 30, 32, 33, 34, 41, 47, 48, 49, 50, 51, 53, 67, 94], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [95, 96], "excluded_lines": []}}, "classes": {"GenerateCLI": {"executed_lines": [55, 56, 57, 60, 62, 65, 76, 78, 79, 80, 81, 82, 84, 89, 91], "summary": {"covered_lines": 15, "num_statements": 17, "percent_covered": 88.23529411764706, "percent_covered_display": "88", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [58, 63], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 13, 14, 16, 17, 26, 29, 30, 32, 33, 34, 41, 47, 48, 49, 50, 51, 53, 67, 94], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [95, 96], "excluded_lines": []}}}, "src/lyscripts/data/join.py": {"executed_lines": [1, 3, 5, 6, 8, 9, 10, 13, 14, 16, 17, 19, 75], "summary": {"covered_lines": 11, "num_statements": 20, "percent_covered": 55.0, "percent_covered_display": "55", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [59, 61, 62, 63, 64, 66, 72, 76, 77], "excluded_lines": [], "functions": {"JoinCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [59, 61, 62, 63, 64, 66, 72], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 8, 9, 10, 13, 14, 16, 17, 19, 75], "summary": {"covered_lines": 11, "num_statements": 13, "percent_covered": 84.61538461538461, "percent_covered_display": "85", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [76, 77], "excluded_lines": []}}, "classes": {"JoinCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [59, 61, 62, 63, 64, 66, 72], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 8, 9, 10, 13, 14, 16, 17, 19, 75], "summary": {"covered_lines": 11, "num_statements": 13, "percent_covered": 84.61538461538461, "percent_covered_display": "85", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [76, 77], "excluded_lines": []}}}, "src/lyscripts/data/lyproxify.py": {"executed_lines": [1, 10, 11, 12, 13, 15, 16, 17, 19, 20, 21, 22, 24, 27, 35, 47, 48, 50, 51, 55, 65, 72, 76, 78, 120, 121, 124, 143, 160, 161, 162, 163, 165, 167, 174, 197, 198, 199, 200, 201, 202, 203, 204, 206, 208, 211, 283, 308, 325, 326, 328, 329, 330, 332, 333, 334, 337], "summary": {"covered_lines": 54, "num_statements": 121, "percent_covered": 44.62809917355372, "percent_covered_display": "45", "missing_lines": 67, "excluded_lines": 0}, "missing_lines": [29, 30, 32, 37, 38, 39, 41, 42, 44, 88, 90, 94, 100, 101, 102, 103, 104, 106, 107, 108, 109, 111, 112, 114, 115, 117, 130, 132, 133, 134, 139, 140, 171, 248, 250, 251, 253, 254, 256, 257, 258, 259, 260, 261, 262, 263, 265, 266, 269, 270, 274, 279, 280, 291, 292, 293, 295, 296, 297, 298, 300, 301, 302, 304, 305, 338, 339], "excluded_lines": [], "functions": {"ensure_python_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [29, 30, 32], "excluded_lines": []}, "ensure_column_map": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [37, 38, 39, 41, 42, 44], "excluded_lines": []}, "LyproxifyCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [88, 90, 94, 100, 101, 102, 103, 104, 106, 107, 108, 109, 111, 112, 114, 115, 117], "excluded_lines": []}, "clean_header": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [130, 132, 133, 134, 139, 140], "excluded_lines": []}, "get_instruction_depth": {"executed_lines": [160, 161, 162, 163, 165, 167], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [171], "excluded_lines": []}, "generate_markdown_docs": {"executed_lines": [197, 198, 199, 200, 201, 202, 203, 204, 206, 208], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "transform_to_lyprox": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [248, 250, 251, 253, 254, 256, 257, 258, 259, 260, 261, 262, 263, 265, 266, 269, 270, 274, 279, 280], "excluded_lines": []}, "leftright_to_ipsicontra": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [291, 292, 293, 295, 296, 297, 298, 300, 301, 302, 304, 305], "excluded_lines": []}, "exclude_patients": {"executed_lines": [325, 326, 328, 329, 330, 332, 333, 334], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 10, 11, 12, 13, 15, 16, 17, 19, 20, 21, 22, 24, 27, 35, 47, 48, 50, 51, 55, 65, 72, 76, 78, 120, 121, 124, 143, 174, 211, 283, 308, 337], "summary": {"covered_lines": 30, "num_statements": 32, "percent_covered": 93.75, "percent_covered_display": "94", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [338, 339], "excluded_lines": []}}, "classes": {"LyproxifyCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [88, 90, 94, 100, 101, 102, 103, 104, 106, 107, 108, 109, 111, 112, 114, 115, 117], "excluded_lines": []}, "ParsingError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 10, 11, 12, 13, 15, 16, 17, 19, 20, 21, 22, 24, 27, 35, 47, 48, 50, 51, 55, 65, 72, 76, 78, 120, 121, 124, 143, 160, 161, 162, 163, 165, 167, 174, 197, 198, 199, 200, 201, 202, 203, 204, 206, 208, 211, 283, 308, 325, 326, 328, 329, 330, 332, 333, 334, 337], "summary": {"covered_lines": 54, "num_statements": 104, "percent_covered": 51.92307692307692, "percent_covered_display": "52", "missing_lines": 50, "excluded_lines": 0}, "missing_lines": [29, 30, 32, 37, 38, 39, 41, 42, 44, 130, 132, 133, 134, 139, 140, 171, 248, 250, 251, 253, 254, 256, 257, 258, 259, 260, 261, 262, 263, 265, 266, 269, 270, 274, 279, 280, 291, 292, 293, 295, 296, 297, 298, 300, 301, 302, 304, 305, 338, 339], "excluded_lines": []}}}, "src/lyscripts/data/split.py": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 18, 19, 21, 22, 23, 25, 71], "summary": {"covered_lines": 16, "num_statements": 30, "percent_covered": 53.333333333333336, "percent_covered_display": "53", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [33, 35, 36, 38, 40, 46, 50, 51, 54, 59, 61, 65, 72, 73], "excluded_lines": [], "functions": {"SplitCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [33, 35, 36, 38, 40, 46, 50, 51, 54, 59, 61, 65], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 18, 19, 21, 22, 23, 25, 71], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [72, 73], "excluded_lines": []}}, "classes": {"SplitCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [33, 35, 36, 38, 40, 46, 50, 51, 54, 59, 61, 65], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 18, 19, 21, 22, 23, 25, 71], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [72, 73], "excluded_lines": []}}}, "src/lyscripts/data/utils.py": {"executed_lines": [1, 3, 5, 6, 8, 11, 12, 14, 15, 16], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"save_table_to_csv": {"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}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 8, 11, 12], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 8, 11, 12, 14, 15, 16], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/lyscripts/decorators.py": {"executed_lines": [1, 8, 9, 10, 11, 12, 13, 16, 18, 19, 20, 23, 30, 33, 34, 36, 37, 38, 39, 41, 42, 51, 57, 59, 62, 65, 66, 68, 69, 72, 74, 77, 80, 81, 83, 84, 86, 88], "summary": {"covered_lines": 37, "num_statements": 41, "percent_covered": 90.2439024390244, "percent_covered_display": "90", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [53, 54, 55, 70], "excluded_lines": [], "functions": {"assemble_signature": {"executed_lines": [18, 19, 20], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "log_state": {"executed_lines": [30, 59], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "log_state.log_decorator": {"executed_lines": [33, 34, 57], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "log_state.log_decorator.wrapper": {"executed_lines": [36, 37, 38, 39, 41, 42, 51], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [53, 54, 55], "excluded_lines": []}, "check_input_file_exists": {"executed_lines": [65, 66, 74], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "check_input_file_exists.inner": {"executed_lines": [68, 69, 72], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [70], "excluded_lines": []}, "check_output_dir_exists": {"executed_lines": [80, 81, 88], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "check_output_dir_exists.inner": {"executed_lines": [83, 84, 86], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 8, 9, 10, 11, 12, 13, 16, 23, 62, 77], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 8, 9, 10, 11, 12, 13, 16, 18, 19, 20, 23, 30, 33, 34, 36, 37, 38, 39, 41, 42, 51, 57, 59, 62, 65, 66, 68, 69, 72, 74, 77, 80, 81, 83, 84, 86, 88], "summary": {"covered_lines": 37, "num_statements": 41, "percent_covered": 90.2439024390244, "percent_covered_display": "90", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [53, 54, 55, 70], "excluded_lines": []}}}, "src/lyscripts/evaluate.py": {"executed_lines": [1, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 21, 24, 38, 73, 90, 112, 144, 207], "summary": {"covered_lines": 18, "num_statements": 75, "percent_covered": 24.0, "percent_covered_display": "24", "missing_lines": 57, "excluded_lines": 0}, "missing_lines": [29, 35, 43, 48, 50, 57, 63, 70, 87, 104, 105, 106, 107, 108, 109, 120, 121, 123, 124, 129, 130, 131, 133, 134, 135, 137, 138, 139, 141, 146, 148, 149, 150, 151, 152, 155, 156, 163, 169, 171, 181, 182, 185, 186, 187, 190, 191, 193, 198, 199, 201, 202, 204, 208, 209, 211, 212], "excluded_lines": [], "functions": {"_add_parser": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [29, 35], "excluded_lines": []}, "_add_arguments": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [43, 48, 50, 57, 63, 70], "excluded_lines": []}, "comp_bic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [87], "excluded_lines": []}, "compute_evidence": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [104, 105, 106, 107, 108, 109], "excluded_lines": []}, "compute_ti_results": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [120, 121, 123, 124, 129, 130, 131, 133, 134, 135, 137, 138, 139, 141], "excluded_lines": []}, "main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 0}, "missing_lines": [146, 148, 149, 150, 151, 152, 155, 156, 163, 169, 171, 181, 182, 185, 186, 187, 190, 191, 193, 198, 199, 201, 202, 204], "excluded_lines": []}, "": {"executed_lines": [1, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 21, 24, 38, 73, 90, 112, 144, 207], "summary": {"covered_lines": 18, "num_statements": 22, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [208, 209, 211, 212], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 21, 24, 38, 73, 90, 112, 144, 207], "summary": {"covered_lines": 18, "num_statements": 75, "percent_covered": 24.0, "percent_covered_display": "24", "missing_lines": 57, "excluded_lines": 0}, "missing_lines": [29, 35, 43, 48, 50, 57, 63, 70, 87, 104, 105, 106, 107, 108, 109, 120, 121, 123, 124, 129, 130, 131, 133, 134, 135, 137, 138, 139, 141, 146, 148, 149, 150, 151, 152, 155, 156, 163, 169, 171, 181, 182, 185, 186, 187, 190, 191, 193, 198, 199, 201, 202, 204, 208, 209, 211, 212], "excluded_lines": []}}}, "src/lyscripts/plots.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 25, 30, 37, 38, 41, 50, 59, 61, 64, 66, 69, 74, 75, 76, 77, 78, 81, 84, 85, 87, 88, 89, 91, 92, 96, 97, 101, 102, 106, 109, 110, 112, 115, 116, 118, 120, 121, 123, 125, 126, 135, 136, 137, 138, 139, 140, 142, 144, 146, 148, 150, 152, 154, 155, 157, 158, 160, 163, 164, 166, 167, 169, 170, 179, 180, 181, 182, 183, 184, 190, 198, 199, 201, 202, 204, 206, 208, 216, 218, 225, 227, 234, 239, 240, 241, 243, 244, 246, 247, 249, 252, 268, 269, 270, 271, 273, 274, 275, 276, 279, 281, 282, 288, 289, 290, 291, 294, 303, 306, 307, 310, 311, 314, 335, 338, 340, 343, 345, 354, 355, 357, 358, 360, 363, 395, 396, 397, 402, 403, 404, 410, 411], "summary": {"covered_lines": 143, "num_statements": 166, "percent_covered": 86.144578313253, "percent_covered_display": "86", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [26, 27, 46, 47, 56, 94, 99, 104, 185, 186, 336, 341, 370, 375, 377, 378, 380, 381, 382, 383, 385, 392, 399], "excluded_lines": [], "functions": {"floor_at_decimal": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [46, 47], "excluded_lines": []}, "ceil_at_decimal": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [56], "excluded_lines": []}, "floor_to_step": {"executed_lines": [61], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ceil_to_step": {"executed_lines": [66], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "clean_and_check": {"executed_lines": [74, 75, 76, 77, 78], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AbstractDistribution.draw": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [94], "excluded_lines": []}, "AbstractDistribution.left_percentile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [99], "excluded_lines": []}, "AbstractDistribution.right_percentile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [104], "excluded_lines": []}, "AbstractDistribution._get_label": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AbstractDistribution.label": {"executed_lines": [112], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.values": {"executed_lines": [123], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.from_hdf5": {"executed_lines": [135, 136, 137, 138, 139, 140], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.left_percentile": {"executed_lines": [144], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.right_percentile": {"executed_lines": [148], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.draw": {"executed_lines": [152, 154, 155, 157, 158, 160], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.from_hdf5": {"executed_lines": [179, 180, 181, 182, 183, 184, 190], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [185, 186], "excluded_lines": []}, "BetaPosterior._get_label": {"executed_lines": [199], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.num_fail": {"executed_lines": [204], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.pdf": {"executed_lines": [208], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.left_percentile": {"executed_lines": [218], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.right_percentile": {"executed_lines": [227], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.draw": {"executed_lines": [239, 240, 241, 243, 244, 246, 247, 249], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_size": {"executed_lines": [268, 269, 270, 271, 273, 274, 275, 276], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_label": {"executed_lines": [281, 282, 288, 289, 290, 291], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_xlims": {"executed_lines": [303, 306, 307, 310, 311], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "draw": {"executed_lines": [335, 338, 340, 343, 345, 354, 355, 357, 358, 360], "summary": {"covered_lines": 10, "num_statements": 12, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [336, 341], "excluded_lines": []}, "split_legends": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [370, 375, 377, 378, 380, 381, 382, 383, 385, 392], "excluded_lines": []}, "use_mpl_stylesheet": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [399], "excluded_lines": []}, "save_figure": {"executed_lines": [410, 411], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 25, 30, 37, 38, 41, 50, 59, 64, 69, 81, 84, 85, 87, 88, 89, 91, 92, 96, 97, 101, 102, 106, 109, 110, 115, 116, 118, 120, 121, 125, 126, 142, 146, 150, 163, 164, 166, 167, 169, 170, 198, 201, 202, 206, 216, 225, 234, 252, 279, 294, 314, 363, 395, 396, 397, 402, 403, 404], "summary": {"covered_lines": 69, "num_statements": 71, "percent_covered": 97.1830985915493, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [26, 27], "excluded_lines": []}}, "classes": {"AbstractDistribution": {"executed_lines": [112], "summary": {"covered_lines": 1, "num_statements": 4, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [94, 99, 104], "excluded_lines": []}, "Histogram": {"executed_lines": [123, 135, 136, 137, 138, 139, 140, 144, 148, 152, 154, 155, 157, 158, 160], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior": {"executed_lines": [179, 180, 181, 182, 183, 184, 190, 199, 204, 208, 218, 227, 239, 240, 241, 243, 244, 246, 247, 249], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [185, 186], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 25, 30, 37, 38, 41, 50, 59, 61, 64, 66, 69, 74, 75, 76, 77, 78, 81, 84, 85, 87, 88, 89, 91, 92, 96, 97, 101, 102, 106, 109, 110, 115, 116, 118, 120, 121, 125, 126, 142, 146, 150, 163, 164, 166, 167, 169, 170, 198, 201, 202, 206, 216, 225, 234, 252, 268, 269, 270, 271, 273, 274, 275, 276, 279, 281, 282, 288, 289, 290, 291, 294, 303, 306, 307, 310, 311, 314, 335, 338, 340, 343, 345, 354, 355, 357, 358, 360, 363, 395, 396, 397, 402, 403, 404, 410, 411], "summary": {"covered_lines": 107, "num_statements": 125, "percent_covered": 85.6, "percent_covered_display": "86", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [26, 27, 46, 47, 56, 336, 341, 370, 375, 377, 378, 380, 381, 382, 383, 385, 392, 399], "excluded_lines": []}}}, "src/lyscripts/sample.py": {"executed_lines": [1, 19, 21, 22, 23, 25, 27, 29, 30, 31, 32, 34, 38, 40, 41, 42, 43, 44, 45, 46, 47, 49, 60, 63, 64, 66, 68, 69, 71, 73, 75, 78, 79, 81, 83, 84, 85, 86, 89, 90, 92, 93, 95, 97, 98, 100, 101, 103, 106, 107, 109, 110, 112, 114, 115, 117, 118, 120, 123, 126, 135, 140, 141, 142, 146, 147, 148, 150, 153, 162, 163, 175, 184, 185, 187, 190, 193, 209, 215, 217, 225, 257, 258, 260, 261, 262, 264, 265, 267, 268, 269, 270, 275, 277, 278, 280, 291, 297, 298, 300, 304, 305, 307, 311, 316, 322, 325, 327, 328, 334, 347, 348, 350, 351, 352, 359, 365, 366, 368, 385, 387, 391, 392, 393, 394, 395, 398, 400, 401, 402, 410, 419], "summary": {"covered_lines": 125, "num_statements": 136, "percent_covered": 91.91176470588235, "percent_covered_display": "92", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [35, 36, 74, 132, 172, 188, 301, 309, 313, 420, 421], "excluded_lines": [], "functions": {"CompletedItersColumn.__init__": {"executed_lines": [68, 69], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "CompletedItersColumn.render": {"executed_lines": [73, 75], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [74], "excluded_lines": []}, "ItersPerSecondColumn.render": {"executed_lines": [83, 84, 85, 86], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AcorTime.update": {"executed_lines": [97, 98], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AcorTime.relative_diff": {"executed_lines": [103], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NumAccepted.update": {"executed_lines": [114, 115], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NumAccepted.newly_accepted": {"executed_lines": [120], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "log_prob_fn": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [132], "excluded_lines": []}, "ensure_initial_state": {"executed_lines": [140, 141, 142, 146, 147, 148, 150], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ensure_history_table": {"executed_lines": [162, 163], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [172], "excluded_lines": []}, "update_history_table": {"executed_lines": [184, 185, 187, 190], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [188], "excluded_lines": []}, "is_converged": {"executed_lines": [209], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_get_columns": {"executed_lines": [217], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "run_sampling": {"executed_lines": [257, 258, 260, 261, 262, 264, 265, 267, 268, 269, 270, 275, 277, 278, 280, 291, 297, 298, 300], "summary": {"covered_lines": 19, "num_statements": 20, "percent_covered": 95.0, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [301], "excluded_lines": []}, "DummyPool.__enter__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [309], "excluded_lines": []}, "DummyPool.__exit__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [313], "excluded_lines": []}, "get_pool": {"executed_lines": [322], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "init_sampler": {"executed_lines": [327, 328, 334], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SampleCLI.cli_cmd": {"executed_lines": [385, 387, 391, 392, 393, 394, 395, 398, 400, 401, 402, 410], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 19, 21, 22, 23, 25, 27, 29, 30, 31, 32, 34, 38, 40, 41, 42, 43, 44, 45, 46, 47, 49, 60, 63, 64, 66, 71, 78, 79, 81, 89, 90, 92, 93, 95, 100, 101, 106, 107, 109, 110, 112, 117, 118, 123, 126, 135, 153, 175, 193, 215, 225, 304, 305, 307, 311, 316, 325, 347, 348, 350, 351, 352, 359, 365, 366, 368, 419], "summary": {"covered_lines": 61, "num_statements": 65, "percent_covered": 93.84615384615384, "percent_covered_display": "94", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [35, 36, 420, 421], "excluded_lines": []}}, "classes": {"CompletedItersColumn": {"executed_lines": [68, 69, 73, 75], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [74], "excluded_lines": []}, "ItersPerSecondColumn": {"executed_lines": [83, 84, 85, 86], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AcorTime": {"executed_lines": [97, 98, 103], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NumAccepted": {"executed_lines": [114, 115, 120], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyPool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [309, 313], "excluded_lines": []}, "SampleCLI": {"executed_lines": [385, 387, 391, 392, 393, 394, 395, 398, 400, 401, 402, 410], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 19, 21, 22, 23, 25, 27, 29, 30, 31, 32, 34, 38, 40, 41, 42, 43, 44, 45, 46, 47, 49, 60, 63, 64, 66, 71, 78, 79, 81, 89, 90, 92, 93, 95, 100, 101, 106, 107, 109, 110, 112, 117, 118, 123, 126, 135, 140, 141, 142, 146, 147, 148, 150, 153, 162, 163, 175, 184, 185, 187, 190, 193, 209, 215, 217, 225, 257, 258, 260, 261, 262, 264, 265, 267, 268, 269, 270, 275, 277, 278, 280, 291, 297, 298, 300, 304, 305, 307, 311, 316, 322, 325, 327, 328, 334, 347, 348, 350, 351, 352, 359, 365, 366, 368, 419], "summary": {"covered_lines": 99, "num_statements": 107, "percent_covered": 92.5233644859813, "percent_covered_display": "93", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [35, 36, 132, 172, 188, 301, 420, 421], "excluded_lines": []}}}, "src/lyscripts/schedule.py": {"executed_lines": [1, 13, 15, 16, 17, 19, 20, 23, 30, 38, 48, 55, 56, 58, 62, 66, 71, 83], "summary": {"covered_lines": 16, "num_statements": 29, "percent_covered": 55.172413793103445, "percent_covered_display": "55", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [25, 26, 27, 35, 44, 45, 73, 75, 76, 78, 80, 84, 85], "excluded_lines": [], "functions": {"geometric_schedule": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [25, 26, 27], "excluded_lines": []}, "linear_schedule": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [35], "excluded_lines": []}, "power_schedule": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [44, 45], "excluded_lines": []}, "ScheduleCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [73, 75, 76, 78, 80], "excluded_lines": []}, "": {"executed_lines": [1, 13, 15, 16, 17, 19, 20, 23, 30, 38, 48, 55, 56, 58, 62, 66, 71, 83], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [84, 85], "excluded_lines": []}}, "classes": {"ScheduleCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [73, 75, 76, 78, 80], "excluded_lines": []}, "": {"executed_lines": [1, 13, 15, 16, 17, 19, 20, 23, 30, 38, 48, 55, 56, 58, 62, 66, 71, 83], "summary": {"covered_lines": 16, "num_statements": 24, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [25, 26, 27, 35, 44, 45, 84, 85], "excluded_lines": []}}}, "src/lyscripts/schema.py": {"executed_lines": [1, 27, 29, 30, 32, 35, 36, 38, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 58, 64], "summary": {"covered_lines": 18, "num_statements": 21, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [60, 61, 65], "excluded_lines": [], "functions": {"main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [60, 61], "excluded_lines": []}, "": {"executed_lines": [1, 27, 29, 30, 32, 35, 36, 38, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 58, 64], "summary": {"covered_lines": 18, "num_statements": 19, "percent_covered": 94.73684210526316, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [65], "excluded_lines": []}}, "classes": {"SchemaSettings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 27, 29, 30, 32, 35, 36, 38, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 58, 64], "summary": {"covered_lines": 18, "num_statements": 21, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [60, 61, 65], "excluded_lines": []}}}, "src/lyscripts/utils.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 18, 21, 23, 24, 26, 27, 30, 33, 42, 43, 45, 46, 47, 48, 50, 53, 63, 65, 66, 67, 68, 70, 72, 75, 91, 93, 94, 95, 97, 98, 100, 102, 105, 115, 117, 118, 119, 120, 122, 124, 127, 137, 138, 139, 140, 143, 146, 151, 152, 154, 155, 156, 159, 160, 162, 163, 164, 165, 168, 169, 177, 178, 179, 180, 183, 184, 192, 193, 195, 199], "summary": {"covered_lines": 79, "num_statements": 84, "percent_covered": 94.04761904761905, "percent_covered_display": "94", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [25, 141, 142, 196, 197], "excluded_lines": [], "functions": {"binom_pmf": {"executed_lines": [23, 24, 26, 27, 30], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [25], "excluded_lines": []}, "get_dict_depth": {"executed_lines": [42, 43, 45, 46, 47, 48, 50], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "delete_private_keys": {"executed_lines": [63, 65, 66, 67, 68, 70, 72], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "flatten": {"executed_lines": [91, 93, 94, 95, 97, 98, 100, 102], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "unflatten": {"executed_lines": [115, 117, 118, 119, 120, 122, 124], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_modalities_subset": {"executed_lines": [137, 138, 139, 140, 143], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [141, 142], "excluded_lines": []}, "load_patient_data": {"executed_lines": [151, 152, 154, 155, 156], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "load_yaml_params": {"executed_lines": [162, 163, 164, 165], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "load_model_samples": {"executed_lines": [177, 178, 179, 180], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_hdf5_backend": {"executed_lines": [192, 193, 195, 199], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [196, 197], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 18, 21, 33, 53, 75, 105, 127, 146, 159, 160, 168, 169, 183, 184], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 18, 21, 23, 24, 26, 27, 30, 33, 42, 43, 45, 46, 47, 48, 50, 53, 63, 65, 66, 67, 68, 70, 72, 75, 91, 93, 94, 95, 97, 98, 100, 102, 105, 115, 117, 118, 119, 120, 122, 124, 127, 137, 138, 139, 140, 143, 146, 151, 152, 154, 155, 156, 159, 160, 162, 163, 164, 165, 168, 169, 177, 178, 179, 180, 183, 184, 192, 193, 195, 199], "summary": {"covered_lines": 79, "num_statements": 84, "percent_covered": 94.04761904761905, "percent_covered_display": "94", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [25, 141, 142, 196, 197], "excluded_lines": []}}}}, "totals": {"covered_lines": 1159, "num_statements": 1551, "percent_covered": 74.72598323662153, "percent_covered_display": "75", "missing_lines": 392, "excluded_lines": 0}}, "coverage_path": "."} \ No newline at end of file diff --git a/endpoint.json b/endpoint.json new file mode 100644 index 0000000..7adc848 --- /dev/null +++ b/endpoint.json @@ -0,0 +1 @@ +{"schemaVersion": 1, "label": "Coverage", "message": "74%", "color": "orange"} \ No newline at end of file diff --git a/htmlcov/class_index.html b/htmlcov/class_index.html new file mode 100644 index 0000000..7e51ec3 --- /dev/null +++ b/htmlcov/class_index.html @@ -0,0 +1,596 @@ + + + + + Coverage report + + + + + +
+
+

Coverage report: + 75% +

+ +
+ +
+ + +
+
+

+ Files + Functions + Classes +

+

+ coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Fileclassstatementsmissingexcludedcoverage
src/lyscripts/__init__.pyLyscriptsCLI7700%
src/lyscripts/__init__.py(no class)2700100%
src/lyscripts/__main__.py(no class)3300%
src/lyscripts/_version.py(no class)133077%
src/lyscripts/cli.py(no class)2612054%
src/lyscripts/compute/__init__.pyComputeCLI1100%
src/lyscripts/compute/__init__.py(no class)800100%
src/lyscripts/compute/__main__.py(no class)5500%
src/lyscripts/compute/posteriors.pyPosteriorsCLI171700%
src/lyscripts/compute/posteriors.py(no class)292093%
src/lyscripts/compute/prevalences.pyPrevalencesCLI1900100%
src/lyscripts/compute/prevalences.py(no class)617089%
src/lyscripts/compute/priors.pyPriorsCLI1200100%
src/lyscripts/compute/priors.py(no class)232091%
src/lyscripts/compute/risks.pyRisksCLI222200%
src/lyscripts/compute/risks.py(no class)2911062%
src/lyscripts/compute/utils.pyHDF5FileStorage263088%
src/lyscripts/compute/utils.py(no class)943097%
src/lyscripts/configs.pyDataConfig41075%
src/lyscripts/configs.pyDiagnosisConfig1100%
src/lyscripts/configs.pyGraphConfig200100%
src/lyscripts/configs.pyModelConfig154073%
src/lyscripts/configs.pyDeprecatedModelConfig1900100%
src/lyscripts/configs.pySamplingConfig100100%
src/lyscripts/configs.pyScenarioConfig84050%
src/lyscripts/configs.pyDynamicYamlConfigSettingsSource121092%
src/lyscripts/configs.pyBaseCLI300100%
src/lyscripts/configs.py(no class)19016092%
src/lyscripts/data/__init__.pyDataCLI1100%
src/lyscripts/data/__init__.py(no class)1100100%
src/lyscripts/data/__main__.py(no class)181800%
src/lyscripts/data/enhance.pyEnhanceCLI6600%
src/lyscripts/data/enhance.py(no class)182089%
src/lyscripts/data/filter.pyFilterCLI282800%
src/lyscripts/data/filter.py(no class)212090%
src/lyscripts/data/generate.pyGenerateCLI172088%
src/lyscripts/data/generate.py(no class)222091%
src/lyscripts/data/join.pyJoinCLI7700%
src/lyscripts/data/join.py(no class)132085%
src/lyscripts/data/lyproxify.pyLyproxifyCLI171700%
src/lyscripts/data/lyproxify.py(no class)10450052%
src/lyscripts/data/split.pySplitCLI121200%
src/lyscripts/data/split.py(no class)182089%
src/lyscripts/data/utils.py(no class)900100%
src/lyscripts/decorators.py(no class)414090%
src/lyscripts/evaluate.py(no class)7557024%
src/lyscripts/plots.pyAbstractDistribution43025%
src/lyscripts/plots.pyHistogram1500100%
src/lyscripts/plots.pyBetaPosterior222091%
src/lyscripts/plots.py(no class)12518086%
src/lyscripts/sample.pyCompletedItersColumn51080%
src/lyscripts/sample.pyItersPerSecondColumn400100%
src/lyscripts/sample.pyAcorTime300100%
src/lyscripts/sample.pyNumAccepted300100%
src/lyscripts/sample.pyDummyPool2200%
src/lyscripts/sample.pySampleCLI1200100%
src/lyscripts/sample.py(no class)1078093%
src/lyscripts/schedule.pyScheduleCLI5500%
src/lyscripts/schedule.py(no class)248067%
src/lyscripts/schema.py(no class)213086%
src/lyscripts/utils.py(no class)845094%
Total 1551392075%
+

+ No items found using the specified filter. +

+

6 empty classes skipped.

+
+ + + diff --git a/htmlcov/coverage_html_cb_6fb7b396.js b/htmlcov/coverage_html_cb_6fb7b396.js new file mode 100644 index 0000000..1face13 --- /dev/null +++ b/htmlcov/coverage_html_cb_6fb7b396.js @@ -0,0 +1,733 @@ +// Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +// For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +// Coverage.py HTML report browser code. +/*jslint browser: true, sloppy: true, vars: true, plusplus: true, maxerr: 50, indent: 4 */ +/*global coverage: true, document, window, $ */ + +coverage = {}; + +// General helpers +function debounce(callback, wait) { + let timeoutId = null; + return function(...args) { + clearTimeout(timeoutId); + timeoutId = setTimeout(() => { + callback.apply(this, args); + }, wait); + }; +}; + +function checkVisible(element) { + const rect = element.getBoundingClientRect(); + const viewBottom = Math.max(document.documentElement.clientHeight, window.innerHeight); + const viewTop = 30; + return !(rect.bottom < viewTop || rect.top >= viewBottom); +} + +function on_click(sel, fn) { + const elt = document.querySelector(sel); + if (elt) { + elt.addEventListener("click", fn); + } +} + +// Helpers for table sorting +function getCellValue(row, column = 0) { + const cell = row.cells[column] // nosemgrep: eslint.detect-object-injection + if (cell.childElementCount == 1) { + var child = cell.firstElementChild; + if (child.tagName === "A") { + child = child.firstElementChild; + } + if (child instanceof HTMLDataElement && child.value) { + return child.value; + } + } + return cell.innerText || cell.textContent; +} + +function rowComparator(rowA, rowB, column = 0) { + let valueA = getCellValue(rowA, column); + let valueB = getCellValue(rowB, column); + if (!isNaN(valueA) && !isNaN(valueB)) { + return valueA - valueB; + } + return valueA.localeCompare(valueB, undefined, {numeric: true}); +} + +function sortColumn(th) { + // Get the current sorting direction of the selected header, + // clear state on other headers and then set the new sorting direction. + const currentSortOrder = th.getAttribute("aria-sort"); + [...th.parentElement.cells].forEach(header => header.setAttribute("aria-sort", "none")); + var direction; + if (currentSortOrder === "none") { + direction = th.dataset.defaultSortOrder || "ascending"; + } + else if (currentSortOrder === "ascending") { + direction = "descending"; + } + else { + direction = "ascending"; + } + th.setAttribute("aria-sort", direction); + + const column = [...th.parentElement.cells].indexOf(th) + + // Sort all rows and afterwards append them in order to move them in the DOM. + Array.from(th.closest("table").querySelectorAll("tbody tr")) + .sort((rowA, rowB) => rowComparator(rowA, rowB, column) * (direction === "ascending" ? 1 : -1)) + .forEach(tr => tr.parentElement.appendChild(tr)); + + // Save the sort order for next time. + if (th.id !== "region") { + let th_id = "file"; // Sort by file if we don't have a column id + let current_direction = direction; + const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE); + if (stored_list) { + ({th_id, direction} = JSON.parse(stored_list)) + } + localStorage.setItem(coverage.INDEX_SORT_STORAGE, JSON.stringify({ + "th_id": th.id, + "direction": current_direction + })); + if (th.id !== th_id || document.getElementById("region")) { + // Sort column has changed, unset sorting by function or class. + localStorage.setItem(coverage.SORTED_BY_REGION, JSON.stringify({ + "by_region": false, + "region_direction": current_direction + })); + } + } + else { + // Sort column has changed to by function or class, remember that. + localStorage.setItem(coverage.SORTED_BY_REGION, JSON.stringify({ + "by_region": true, + "region_direction": direction + })); + } +} + +// Find all the elements with data-shortcut attribute, and use them to assign a shortcut key. +coverage.assign_shortkeys = function () { + document.querySelectorAll("[data-shortcut]").forEach(element => { + document.addEventListener("keypress", event => { + if (event.target.tagName.toLowerCase() === "input") { + return; // ignore keypress from search filter + } + if (event.key === element.dataset.shortcut) { + element.click(); + } + }); + }); +}; + +// Create the events for the filter box. +coverage.wire_up_filter = function () { + // Populate the filter and hide100 inputs if there are saved values for them. + const saved_filter_value = localStorage.getItem(coverage.FILTER_STORAGE); + if (saved_filter_value) { + document.getElementById("filter").value = saved_filter_value; + } + const saved_hide100_value = localStorage.getItem(coverage.HIDE100_STORAGE); + if (saved_hide100_value) { + document.getElementById("hide100").checked = JSON.parse(saved_hide100_value); + } + + // Cache elements. + const table = document.querySelector("table.index"); + const table_body_rows = table.querySelectorAll("tbody tr"); + const no_rows = document.getElementById("no_rows"); + + // Observe filter keyevents. + const filter_handler = (event => { + // Keep running total of each metric, first index contains number of shown rows + const totals = new Array(table.rows[0].cells.length).fill(0); + // Accumulate the percentage as fraction + totals[totals.length - 1] = { "numer": 0, "denom": 0 }; // nosemgrep: eslint.detect-object-injection + + var text = document.getElementById("filter").value; + // Store filter value + localStorage.setItem(coverage.FILTER_STORAGE, text); + const casefold = (text === text.toLowerCase()); + const hide100 = document.getElementById("hide100").checked; + // Store hide value. + localStorage.setItem(coverage.HIDE100_STORAGE, JSON.stringify(hide100)); + + // Hide / show elements. + table_body_rows.forEach(row => { + var show = false; + // Check the text filter. + for (let column = 0; column < totals.length; column++) { + cell = row.cells[column]; + if (cell.classList.contains("name")) { + var celltext = cell.textContent; + if (casefold) { + celltext = celltext.toLowerCase(); + } + if (celltext.includes(text)) { + show = true; + } + } + } + + // Check the "hide covered" filter. + if (show && hide100) { + const [numer, denom] = row.cells[row.cells.length - 1].dataset.ratio.split(" "); + show = (numer !== denom); + } + + if (!show) { + // hide + row.classList.add("hidden"); + return; + } + + // show + row.classList.remove("hidden"); + totals[0]++; + + for (let column = 0; column < totals.length; column++) { + // Accumulate dynamic totals + cell = row.cells[column] // nosemgrep: eslint.detect-object-injection + if (cell.classList.contains("name")) { + continue; + } + if (column === totals.length - 1) { + // Last column contains percentage + const [numer, denom] = cell.dataset.ratio.split(" "); + totals[column]["numer"] += parseInt(numer, 10); // nosemgrep: eslint.detect-object-injection + totals[column]["denom"] += parseInt(denom, 10); // nosemgrep: eslint.detect-object-injection + } + else { + totals[column] += parseInt(cell.textContent, 10); // nosemgrep: eslint.detect-object-injection + } + } + }); + + // Show placeholder if no rows will be displayed. + if (!totals[0]) { + // Show placeholder, hide table. + no_rows.style.display = "block"; + table.style.display = "none"; + return; + } + + // Hide placeholder, show table. + no_rows.style.display = null; + table.style.display = null; + + const footer = table.tFoot.rows[0]; + // Calculate new dynamic sum values based on visible rows. + for (let column = 0; column < totals.length; column++) { + // Get footer cell element. + const cell = footer.cells[column]; // nosemgrep: eslint.detect-object-injection + if (cell.classList.contains("name")) { + continue; + } + + // Set value into dynamic footer cell element. + if (column === totals.length - 1) { + // Percentage column uses the numerator and denominator, + // and adapts to the number of decimal places. + const match = /\.([0-9]+)/.exec(cell.textContent); + const places = match ? match[1].length : 0; + const { numer, denom } = totals[column]; // nosemgrep: eslint.detect-object-injection + cell.dataset.ratio = `${numer} ${denom}`; + // Check denom to prevent NaN if filtered files contain no statements + cell.textContent = denom + ? `${(numer * 100 / denom).toFixed(places)}%` + : `${(100).toFixed(places)}%`; + } + else { + cell.textContent = totals[column]; // nosemgrep: eslint.detect-object-injection + } + } + }); + + document.getElementById("filter").addEventListener("input", debounce(filter_handler)); + document.getElementById("hide100").addEventListener("input", debounce(filter_handler)); + + // Trigger change event on setup, to force filter on page refresh + // (filter value may still be present). + document.getElementById("filter").dispatchEvent(new Event("input")); + document.getElementById("hide100").dispatchEvent(new Event("input")); +}; +coverage.FILTER_STORAGE = "COVERAGE_FILTER_VALUE"; +coverage.HIDE100_STORAGE = "COVERAGE_HIDE100_VALUE"; + +// Set up the click-to-sort columns. +coverage.wire_up_sorting = function () { + document.querySelectorAll("[data-sortable] th[aria-sort]").forEach( + th => th.addEventListener("click", e => sortColumn(e.target)) + ); + + // Look for a localStorage item containing previous sort settings: + let th_id = "file", direction = "ascending"; + const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE); + if (stored_list) { + ({th_id, direction} = JSON.parse(stored_list)); + } + let by_region = false, region_direction = "ascending"; + const sorted_by_region = localStorage.getItem(coverage.SORTED_BY_REGION); + if (sorted_by_region) { + ({ + by_region, + region_direction + } = JSON.parse(sorted_by_region)); + } + + const region_id = "region"; + if (by_region && document.getElementById(region_id)) { + direction = region_direction; + } + // If we are in a page that has a column with id of "region", sort on + // it if the last sort was by function or class. + let th; + if (document.getElementById(region_id)) { + th = document.getElementById(by_region ? region_id : th_id); + } + else { + th = document.getElementById(th_id); + } + th.setAttribute("aria-sort", direction === "ascending" ? "descending" : "ascending"); + th.click() +}; + +coverage.INDEX_SORT_STORAGE = "COVERAGE_INDEX_SORT_2"; +coverage.SORTED_BY_REGION = "COVERAGE_SORT_REGION"; + +// Loaded on index.html +coverage.index_ready = function () { + coverage.assign_shortkeys(); + coverage.wire_up_filter(); + coverage.wire_up_sorting(); + + on_click(".button_prev_file", coverage.to_prev_file); + on_click(".button_next_file", coverage.to_next_file); + + on_click(".button_show_hide_help", coverage.show_hide_help); +}; + +// -- pyfile stuff -- + +coverage.LINE_FILTERS_STORAGE = "COVERAGE_LINE_FILTERS"; + +coverage.pyfile_ready = function () { + // If we're directed to a particular line number, highlight the line. + var frag = location.hash; + if (frag.length > 2 && frag[1] === "t") { + document.querySelector(frag).closest(".n").classList.add("highlight"); + coverage.set_sel(parseInt(frag.substr(2), 10)); + } + else { + coverage.set_sel(0); + } + + on_click(".button_toggle_run", coverage.toggle_lines); + on_click(".button_toggle_mis", coverage.toggle_lines); + on_click(".button_toggle_exc", coverage.toggle_lines); + on_click(".button_toggle_par", coverage.toggle_lines); + + on_click(".button_next_chunk", coverage.to_next_chunk_nicely); + on_click(".button_prev_chunk", coverage.to_prev_chunk_nicely); + on_click(".button_top_of_page", coverage.to_top); + on_click(".button_first_chunk", coverage.to_first_chunk); + + on_click(".button_prev_file", coverage.to_prev_file); + on_click(".button_next_file", coverage.to_next_file); + on_click(".button_to_index", coverage.to_index); + + on_click(".button_show_hide_help", coverage.show_hide_help); + + coverage.filters = undefined; + try { + coverage.filters = localStorage.getItem(coverage.LINE_FILTERS_STORAGE); + } catch(err) {} + + if (coverage.filters) { + coverage.filters = JSON.parse(coverage.filters); + } + else { + coverage.filters = {run: false, exc: true, mis: true, par: true}; + } + + for (cls in coverage.filters) { + coverage.set_line_visibilty(cls, coverage.filters[cls]); // nosemgrep: eslint.detect-object-injection + } + + coverage.assign_shortkeys(); + coverage.init_scroll_markers(); + coverage.wire_up_sticky_header(); + + document.querySelectorAll("[id^=ctxs]").forEach( + cbox => cbox.addEventListener("click", coverage.expand_contexts) + ); + + // Rebuild scroll markers when the window height changes. + window.addEventListener("resize", coverage.build_scroll_markers); +}; + +coverage.toggle_lines = function (event) { + const btn = event.target.closest("button"); + const category = btn.value + const show = !btn.classList.contains("show_" + category); + coverage.set_line_visibilty(category, show); + coverage.build_scroll_markers(); + coverage.filters[category] = show; + try { + localStorage.setItem(coverage.LINE_FILTERS_STORAGE, JSON.stringify(coverage.filters)); + } catch(err) {} +}; + +coverage.set_line_visibilty = function (category, should_show) { + const cls = "show_" + category; + const btn = document.querySelector(".button_toggle_" + category); + if (btn) { + if (should_show) { + document.querySelectorAll("#source ." + category).forEach(e => e.classList.add(cls)); + btn.classList.add(cls); + } + else { + document.querySelectorAll("#source ." + category).forEach(e => e.classList.remove(cls)); + btn.classList.remove(cls); + } + } +}; + +// Return the nth line div. +coverage.line_elt = function (n) { + return document.getElementById("t" + n)?.closest("p"); +}; + +// Set the selection. b and e are line numbers. +coverage.set_sel = function (b, e) { + // The first line selected. + coverage.sel_begin = b; + // The next line not selected. + coverage.sel_end = (e === undefined) ? b+1 : e; +}; + +coverage.to_top = function () { + coverage.set_sel(0, 1); + coverage.scroll_window(0); +}; + +coverage.to_first_chunk = function () { + coverage.set_sel(0, 1); + coverage.to_next_chunk(); +}; + +coverage.to_prev_file = function () { + window.location = document.getElementById("prevFileLink").href; +} + +coverage.to_next_file = function () { + window.location = document.getElementById("nextFileLink").href; +} + +coverage.to_index = function () { + location.href = document.getElementById("indexLink").href; +} + +coverage.show_hide_help = function () { + const helpCheck = document.getElementById("help_panel_state") + helpCheck.checked = !helpCheck.checked; +} + +// Return a string indicating what kind of chunk this line belongs to, +// or null if not a chunk. +coverage.chunk_indicator = function (line_elt) { + const classes = line_elt?.className; + if (!classes) { + return null; + } + const match = classes.match(/\bshow_\w+\b/); + if (!match) { + return null; + } + return match[0]; +}; + +coverage.to_next_chunk = function () { + const c = coverage; + + // Find the start of the next colored chunk. + var probe = c.sel_end; + var chunk_indicator, probe_line; + while (true) { + probe_line = c.line_elt(probe); + if (!probe_line) { + return; + } + chunk_indicator = c.chunk_indicator(probe_line); + if (chunk_indicator) { + break; + } + probe++; + } + + // There's a next chunk, `probe` points to it. + var begin = probe; + + // Find the end of this chunk. + var next_indicator = chunk_indicator; + while (next_indicator === chunk_indicator) { + probe++; + probe_line = c.line_elt(probe); + next_indicator = c.chunk_indicator(probe_line); + } + c.set_sel(begin, probe); + c.show_selection(); +}; + +coverage.to_prev_chunk = function () { + const c = coverage; + + // Find the end of the prev colored chunk. + var probe = c.sel_begin-1; + var probe_line = c.line_elt(probe); + if (!probe_line) { + return; + } + var chunk_indicator = c.chunk_indicator(probe_line); + while (probe > 1 && !chunk_indicator) { + probe--; + probe_line = c.line_elt(probe); + if (!probe_line) { + return; + } + chunk_indicator = c.chunk_indicator(probe_line); + } + + // There's a prev chunk, `probe` points to its last line. + var end = probe+1; + + // Find the beginning of this chunk. + var prev_indicator = chunk_indicator; + while (prev_indicator === chunk_indicator) { + probe--; + if (probe <= 0) { + return; + } + probe_line = c.line_elt(probe); + prev_indicator = c.chunk_indicator(probe_line); + } + c.set_sel(probe+1, end); + c.show_selection(); +}; + +// Returns 0, 1, or 2: how many of the two ends of the selection are on +// the screen right now? +coverage.selection_ends_on_screen = function () { + if (coverage.sel_begin === 0) { + return 0; + } + + const begin = coverage.line_elt(coverage.sel_begin); + const end = coverage.line_elt(coverage.sel_end-1); + + return ( + (checkVisible(begin) ? 1 : 0) + + (checkVisible(end) ? 1 : 0) + ); +}; + +coverage.to_next_chunk_nicely = function () { + if (coverage.selection_ends_on_screen() === 0) { + // The selection is entirely off the screen: + // Set the top line on the screen as selection. + + // This will select the top-left of the viewport + // As this is most likely the span with the line number we take the parent + const line = document.elementFromPoint(0, 0).parentElement; + if (line.parentElement !== document.getElementById("source")) { + // The element is not a source line but the header or similar + coverage.select_line_or_chunk(1); + } + else { + // We extract the line number from the id + coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10)); + } + } + coverage.to_next_chunk(); +}; + +coverage.to_prev_chunk_nicely = function () { + if (coverage.selection_ends_on_screen() === 0) { + // The selection is entirely off the screen: + // Set the lowest line on the screen as selection. + + // This will select the bottom-left of the viewport + // As this is most likely the span with the line number we take the parent + const line = document.elementFromPoint(document.documentElement.clientHeight-1, 0).parentElement; + if (line.parentElement !== document.getElementById("source")) { + // The element is not a source line but the header or similar + coverage.select_line_or_chunk(coverage.lines_len); + } + else { + // We extract the line number from the id + coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10)); + } + } + coverage.to_prev_chunk(); +}; + +// Select line number lineno, or if it is in a colored chunk, select the +// entire chunk +coverage.select_line_or_chunk = function (lineno) { + var c = coverage; + var probe_line = c.line_elt(lineno); + if (!probe_line) { + return; + } + var the_indicator = c.chunk_indicator(probe_line); + if (the_indicator) { + // The line is in a highlighted chunk. + // Search backward for the first line. + var probe = lineno; + var indicator = the_indicator; + while (probe > 0 && indicator === the_indicator) { + probe--; + probe_line = c.line_elt(probe); + if (!probe_line) { + break; + } + indicator = c.chunk_indicator(probe_line); + } + var begin = probe + 1; + + // Search forward for the last line. + probe = lineno; + indicator = the_indicator; + while (indicator === the_indicator) { + probe++; + probe_line = c.line_elt(probe); + indicator = c.chunk_indicator(probe_line); + } + + coverage.set_sel(begin, probe); + } + else { + coverage.set_sel(lineno); + } +}; + +coverage.show_selection = function () { + // Highlight the lines in the chunk + document.querySelectorAll("#source .highlight").forEach(e => e.classList.remove("highlight")); + for (let probe = coverage.sel_begin; probe < coverage.sel_end; probe++) { + coverage.line_elt(probe).querySelector(".n").classList.add("highlight"); + } + + coverage.scroll_to_selection(); +}; + +coverage.scroll_to_selection = function () { + // Scroll the page if the chunk isn't fully visible. + if (coverage.selection_ends_on_screen() < 2) { + const element = coverage.line_elt(coverage.sel_begin); + coverage.scroll_window(element.offsetTop - 60); + } +}; + +coverage.scroll_window = function (to_pos) { + window.scroll({top: to_pos, behavior: "smooth"}); +}; + +coverage.init_scroll_markers = function () { + // Init some variables + coverage.lines_len = document.querySelectorAll("#source > p").length; + + // Build html + coverage.build_scroll_markers(); +}; + +coverage.build_scroll_markers = function () { + const temp_scroll_marker = document.getElementById("scroll_marker") + if (temp_scroll_marker) temp_scroll_marker.remove(); + // Don't build markers if the window has no scroll bar. + if (document.body.scrollHeight <= window.innerHeight) { + return; + } + + const marker_scale = window.innerHeight / document.body.scrollHeight; + const line_height = Math.min(Math.max(3, window.innerHeight / coverage.lines_len), 10); + + let previous_line = -99, last_mark, last_top; + + const scroll_marker = document.createElement("div"); + scroll_marker.id = "scroll_marker"; + document.getElementById("source").querySelectorAll( + "p.show_run, p.show_mis, p.show_exc, p.show_exc, p.show_par" + ).forEach(element => { + const line_top = Math.floor(element.offsetTop * marker_scale); + const line_number = parseInt(element.querySelector(".n a").id.substr(1)); + + if (line_number === previous_line + 1) { + // If this solid missed block just make previous mark higher. + last_mark.style.height = `${line_top + line_height - last_top}px`; + } + else { + // Add colored line in scroll_marker block. + last_mark = document.createElement("div"); + last_mark.id = `m${line_number}`; + last_mark.classList.add("marker"); + last_mark.style.height = `${line_height}px`; + last_mark.style.top = `${line_top}px`; + scroll_marker.append(last_mark); + last_top = line_top; + } + + previous_line = line_number; + }); + + // Append last to prevent layout calculation + document.body.append(scroll_marker); +}; + +coverage.wire_up_sticky_header = function () { + const header = document.querySelector("header"); + const header_bottom = ( + header.querySelector(".content h2").getBoundingClientRect().top - + header.getBoundingClientRect().top + ); + + function updateHeader() { + if (window.scrollY > header_bottom) { + header.classList.add("sticky"); + } + else { + header.classList.remove("sticky"); + } + } + + window.addEventListener("scroll", updateHeader); + updateHeader(); +}; + +coverage.expand_contexts = function (e) { + var ctxs = e.target.parentNode.querySelector(".ctxs"); + + if (!ctxs.classList.contains("expanded")) { + var ctxs_text = ctxs.textContent; + var width = Number(ctxs_text[0]); + ctxs.textContent = ""; + for (var i = 1; i < ctxs_text.length; i += width) { + key = ctxs_text.substring(i, i + width).trim(); + ctxs.appendChild(document.createTextNode(contexts[key])); + ctxs.appendChild(document.createElement("br")); + } + ctxs.classList.add("expanded"); + } +}; + +document.addEventListener("DOMContentLoaded", () => { + if (document.body.classList.contains("indexfile")) { + coverage.index_ready(); + } + else { + coverage.pyfile_ready(); + } +}); diff --git a/htmlcov/favicon_32_cb_58284776.png b/htmlcov/favicon_32_cb_58284776.png new file mode 100644 index 0000000000000000000000000000000000000000..8649f0475d8d20793b2ec431fe25a186a414cf10 GIT binary patch literal 1732 zcmV;#20QtQP)K2KOkBOVxIZChq#W-v7@TU%U6P(wycKT1hUJUToW3ke1U1ONa4 z000000000000000bb)GRa9mqwR9|UWHy;^RUrt?IT__Y0JUcxmBP0(51q1>E00030 z|NrOz)aw7%8sJzM<5^g%z7^qE`}_Ot|JUUG(NUkWzR|7K?Zo%@_v-8G-1N%N=D$;; zw;keH4dGY$`1t4M=HK_s*zm^0#KgqfwWhe3qO_HtvXYvtjgX>;-~C$L`&k>^R)9)7 zdPh2TL^pCnHC#0+_4D)M`p?qp!pq{jO_{8;$fbaflbx`Tn52n|n}8VFRTA1&ugOP< zPd{uvFjz7t*Vot1&d$l-xWCk}s;sQL&#O(Bskh6gqNJv>#iB=ypG1e3K!K4yc7!~M zfj4S*g^zZ7eP$+_Sl07Z646l;%urinP#D8a6TwRtnLIRcI!r4f@bK~9-`~;E(N?Lv zSEst7s;rcxsi~}{Nsytfz@MtUoR*iFc8!#vvx}Umhm4blk(_~MdVD-@dW&>!Nn~ro z_E~-ESVQAj6Wmn;(olz(O&_{U2*pZBc1aYjMh>Dq3z|6`jW`RDHV=t3I6yRKJ~LOX zz_z!!vbVXPqob#=pj3^VMT?x6t(irRmSKsMo1~LLkB&=#j!=M%NP35mfqim$drWb9 zYIb>no_LUwc!r^NkDzs4YHu@=ZHRzrafWDZd1EhEVq=tGX?tK$pIa)DTh#bkvh!J- z?^%@YS!U*0E8$q$_*aOTQ&)Ra64g>ep;BdcQgvlg8qQHrP*E$;P{-m=A*@axn@$bO zO-Y4JzS&EAi%YG}N?cn?YFS7ivPY=EMV6~YH;+Xxu|tefLS|Aza)Cg6us#)=JW!uH zQa?H>d^j+YHCtyjL^LulF*05|F$RG!AX_OHVI&MtA~_@=5_lU|0000rbW%=J06GH4 z^5LD8b8apw8vNh1ua1mF{{Hy)_U`NA;Nacc+sCpuHXa-V{r&yz?c(9#+}oX+NmiRW z+W-IqK1oDDR5;6GfCDCOP5}iL5fK(cB~ET81`MFgF2kGa9AjhSIk~-E-4&*tPPKdiilQJ11k_J082ZS z>@TvivP!5ZFG?t@{t+GpR3XR&@*hA_VE1|Lo8@L@)l*h(Z@=?c-NS$Fk&&61IzUU9 z*nPqBM=OBZ-6ka1SJgGAS-Us5EN)r#dUX%>wQZLa2ytPCtMKp)Ob z*xcu38Z&d5<-NBS)@jRD+*!W*cf-m_wmxDEqBf?czI%3U0J$Xik;lA`jg}VH?(S(V zE!M3;X2B8w0TnnW&6(8;_Uc)WD;Ms6PKP+s(sFgO!}B!^ES~GDt4qLPxwYB)^7)XA zZwo9zDy-B0B+jT6V=!=bo(zs_8{eBA78gT9GH$(DVhz;4VAYwz+bOIdZ-PNb|I&rl z^XG=vFLF)1{&nT2*0vMz#}7^9hXzzf&ZdKlEj{LihP;|;Ywqn35ajP?H?7t|i-Un% z&&kxee@9B{nwgv1+S-~0)E1{ob1^Wn`F2isurqThKK=3%&;`@{0{!D- z&CSj80t;uPu&FaJFtSXKH#ajgGj}=sEad7US6jP0|Db@0j)?(5@sf<7`~a9>s;wCa zm^)spe{uxGFmrJYI9cOh7s$>8Npkt-5EWB1UKc`{W{y5Ce$1+nM9Cr;);=Ju#N^62OSlJMn7omiUgP&ErsYzT~iGxcW aE(`!K@+CXylaC4j0000 + + + + Coverage report + + + + + +
+
+

Coverage report: + 75% +

+ +
+ +
+ + +
+
+

+ Files + Functions + Classes +

+

+ coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Filefunctionstatementsmissingexcludedcoverage
src/lyscripts/__init__.pyLyscriptsCLI.__init__2200%
src/lyscripts/__init__.pyLyscriptsCLI.cli_cmd5500%
src/lyscripts/__init__.py(no function)2700100%
src/lyscripts/__main__.py(no function)3300%
src/lyscripts/_version.py(no function)133077%
src/lyscripts/cli.pyassemble_main200100%
src/lyscripts/cli.pyassemble_main.main200100%
src/lyscripts/cli.pysomewhat_safely_get_loglevel6600%
src/lyscripts/cli.pyconfigure_logging6600%
src/lyscripts/cli.py(no function)1000100%
src/lyscripts/compute/__init__.pyComputeCLI.cli_cmd1100%
src/lyscripts/compute/__init__.py(no function)800100%
src/lyscripts/compute/__main__.py(no function)5500%
src/lyscripts/compute/posteriors.pycompute_posteriors1000100%
src/lyscripts/compute/posteriors.pyPosteriorsCLI.cli_cmd171700%
src/lyscripts/compute/posteriors.py(no function)192089%
src/lyscripts/compute/prevalences.pycompute_prevalences205075%
src/lyscripts/compute/prevalences.pygenerate_query_from_diagnosis700100%
src/lyscripts/compute/prevalences.pyobserve_prevalence700100%
src/lyscripts/compute/prevalences.pyPrevalencesCLI.cli_cmd1900100%
src/lyscripts/compute/prevalences.py(no function)272093%
src/lyscripts/compute/priors.pycompute_priors700100%
src/lyscripts/compute/priors.pyPriorsCLI.cli_cmd1200100%
src/lyscripts/compute/priors.py(no function)162088%
src/lyscripts/compute/risks.pycompute_risks9900%
src/lyscripts/compute/risks.pyRisksCLI.cli_cmd222200%
src/lyscripts/compute/risks.py(no function)202090%
src/lyscripts/compute/utils.pyis_hdf5_compatible100100%
src/lyscripts/compute/utils.pyto_hdf5_attrs600100%
src/lyscripts/compute/utils.pyfrom_hdf5_attrs700100%
src/lyscripts/compute/utils.pyextract_modalities71086%
src/lyscripts/compute/utils.pyensure_parent_dir300100%
src/lyscripts/compute/utils.pyHDF5FileStorage._get_dataset41075%
src/lyscripts/compute/utils.pyHDF5FileStorage.load500100%
src/lyscripts/compute/utils.pyHDF5FileStorage.get_attrs500100%
src/lyscripts/compute/utils.pyHDF5FileStorage.save61083%
src/lyscripts/compute/utils.pyHDF5FileStorage.set_attrs61083%
src/lyscripts/compute/utils.pyreduce_pattern900100%
src/lyscripts/compute/utils.pycomplete_pattern122083%
src/lyscripts/compute/utils.pyget_cached700100%
src/lyscripts/compute/utils.pyget_cached.log_cache_info_wrapper700100%
src/lyscripts/compute/utils.py(no function)3500100%
src/lyscripts/configs.pyDataConfig.load31067%
src/lyscripts/configs.pyDataConfig.get_load_kwargs100100%
src/lyscripts/configs.pycheck_pattern100100%
src/lyscripts/configs.pyDiagnosisConfig.to_involvement1100%
src/lyscripts/configs.pyretrieve_graph_representation92078%
src/lyscripts/configs.pyGraphConfig.from_model200100%
src/lyscripts/configs.pyhas_model_symbol600100%
src/lyscripts/configs.pyget_symmetry_kwargs51080%
src/lyscripts/configs.pyModelConfig.from_model154073%
src/lyscripts/configs.pymodalityconfig_from_model200100%
src/lyscripts/configs.pyDeprecatedModelConfig.model_post_init500100%
src/lyscripts/configs.pyDeprecatedModelConfig.translate1400100%
src/lyscripts/configs.pySamplingConfig.load100100%
src/lyscripts/configs.pymap_to_optional_bool51080%
src/lyscripts/configs.pyScenarioConfig.model_post_init200100%
src/lyscripts/configs.pyScenarioConfig.interpolate43025%
src/lyscripts/configs.pyScenarioConfig.normalize21050%
src/lyscripts/configs.py_construct_model_from_external600100%
src/lyscripts/configs.pyconstruct_model700100%
src/lyscripts/configs.pyadd_distributions181094%
src/lyscripts/configs.pyadd_modalities800100%
src/lyscripts/configs.pyadd_data111100%
src/lyscripts/configs.pyDynamicYamlConfigSettingsSource.__init__200100%
src/lyscripts/configs.pyDynamicYamlConfigSettingsSource._read_file51080%
src/lyscripts/configs.pyDynamicYamlConfigSettingsSource.__call__400100%
src/lyscripts/configs.pyDynamicYamlConfigSettingsSource.__repr__100100%
src/lyscripts/configs.pyBaseCLI.settings_customise_sources300100%
src/lyscripts/configs.py(no function)11200100%
src/lyscripts/data/__init__.pyDataCLI.cli_cmd1100%
src/lyscripts/data/__init__.py(no function)1100100%
src/lyscripts/data/__main__.pymain101000%
src/lyscripts/data/__main__.py(no function)8800%
src/lyscripts/data/enhance.pyEnhanceCLI.cli_cmd6600%
src/lyscripts/data/enhance.py(no function)182089%
src/lyscripts/data/filter.pyFilterCLI.model_post_init171700%
src/lyscripts/data/filter.pyFilterCLI.cli_cmd111100%
src/lyscripts/data/filter.py(no function)212090%
src/lyscripts/data/generate.pyGenerateCLI.model_post_init82075%
src/lyscripts/data/generate.pyGenerateCLI.cli_cmd900100%
src/lyscripts/data/generate.py(no function)222091%
src/lyscripts/data/join.pyJoinCLI.cli_cmd7700%
src/lyscripts/data/join.py(no function)132085%
src/lyscripts/data/lyproxify.pyensure_python_file3300%
src/lyscripts/data/lyproxify.pyensure_column_map6600%
src/lyscripts/data/lyproxify.pyLyproxifyCLI.cli_cmd171700%
src/lyscripts/data/lyproxify.pyclean_header6600%
src/lyscripts/data/lyproxify.pyget_instruction_depth71086%
src/lyscripts/data/lyproxify.pygenerate_markdown_docs1000100%
src/lyscripts/data/lyproxify.pytransform_to_lyprox202000%
src/lyscripts/data/lyproxify.pyleftright_to_ipsicontra121200%
src/lyscripts/data/lyproxify.pyexclude_patients800100%
src/lyscripts/data/lyproxify.py(no function)322094%
src/lyscripts/data/split.pySplitCLI.cli_cmd121200%
src/lyscripts/data/split.py(no function)182089%
src/lyscripts/data/utils.pysave_table_to_csv300100%
src/lyscripts/data/utils.py(no function)600100%
src/lyscripts/decorators.pyassemble_signature300100%
src/lyscripts/decorators.pylog_state200100%
src/lyscripts/decorators.pylog_state.log_decorator300100%
src/lyscripts/decorators.pylog_state.log_decorator.wrapper103070%
src/lyscripts/decorators.pycheck_input_file_exists300100%
src/lyscripts/decorators.pycheck_input_file_exists.inner41075%
src/lyscripts/decorators.pycheck_output_dir_exists300100%
src/lyscripts/decorators.pycheck_output_dir_exists.inner300100%
src/lyscripts/decorators.py(no function)1000100%
src/lyscripts/evaluate.py_add_parser2200%
src/lyscripts/evaluate.py_add_arguments6600%
src/lyscripts/evaluate.pycomp_bic1100%
src/lyscripts/evaluate.pycompute_evidence6600%
src/lyscripts/evaluate.pycompute_ti_results141400%
src/lyscripts/evaluate.pymain242400%
src/lyscripts/evaluate.py(no function)224082%
src/lyscripts/plots.pyfloor_at_decimal2200%
src/lyscripts/plots.pyceil_at_decimal1100%
src/lyscripts/plots.pyfloor_to_step100100%
src/lyscripts/plots.pyceil_to_step100100%
src/lyscripts/plots.pyclean_and_check500100%
src/lyscripts/plots.pyAbstractDistribution.draw1100%
src/lyscripts/plots.pyAbstractDistribution.left_percentile1100%
src/lyscripts/plots.pyAbstractDistribution.right_percentile1100%
src/lyscripts/plots.pyAbstractDistribution.label100100%
src/lyscripts/plots.pyHistogram.values100100%
src/lyscripts/plots.pyHistogram.from_hdf5600100%
src/lyscripts/plots.pyHistogram.left_percentile100100%
src/lyscripts/plots.pyHistogram.right_percentile100100%
src/lyscripts/plots.pyHistogram.draw600100%
src/lyscripts/plots.pyBetaPosterior.from_hdf592078%
src/lyscripts/plots.pyBetaPosterior._get_label100100%
src/lyscripts/plots.pyBetaPosterior.num_fail100100%
src/lyscripts/plots.pyBetaPosterior.pdf100100%
src/lyscripts/plots.pyBetaPosterior.left_percentile100100%
src/lyscripts/plots.pyBetaPosterior.right_percentile100100%
src/lyscripts/plots.pyBetaPosterior.draw800100%
src/lyscripts/plots.pyget_size800100%
src/lyscripts/plots.pyget_label600100%
src/lyscripts/plots.pyget_xlims500100%
src/lyscripts/plots.pydraw122083%
src/lyscripts/plots.pysplit_legends101000%
src/lyscripts/plots.pyuse_mpl_stylesheet1100%
src/lyscripts/plots.pysave_figure200100%
src/lyscripts/plots.py(no function)712097%
src/lyscripts/sample.pyCompletedItersColumn.__init__200100%
src/lyscripts/sample.pyCompletedItersColumn.render31067%
src/lyscripts/sample.pyItersPerSecondColumn.render400100%
src/lyscripts/sample.pyAcorTime.update200100%
src/lyscripts/sample.pyAcorTime.relative_diff100100%
src/lyscripts/sample.pyNumAccepted.update200100%
src/lyscripts/sample.pyNumAccepted.newly_accepted100100%
src/lyscripts/sample.pylog_prob_fn1100%
src/lyscripts/sample.pyensure_initial_state700100%
src/lyscripts/sample.pyensure_history_table31067%
src/lyscripts/sample.pyupdate_history_table51080%
src/lyscripts/sample.pyis_converged100100%
src/lyscripts/sample.py_get_columns100100%
src/lyscripts/sample.pyrun_sampling201095%
src/lyscripts/sample.pyDummyPool.__enter__1100%
src/lyscripts/sample.pyDummyPool.__exit__1100%
src/lyscripts/sample.pyget_pool100100%
src/lyscripts/sample.pyinit_sampler300100%
src/lyscripts/sample.pySampleCLI.cli_cmd1200100%
src/lyscripts/sample.py(no function)654094%
src/lyscripts/schedule.pygeometric_schedule3300%
src/lyscripts/schedule.pylinear_schedule1100%
src/lyscripts/schedule.pypower_schedule2200%
src/lyscripts/schedule.pyScheduleCLI.cli_cmd5500%
src/lyscripts/schedule.py(no function)182089%
src/lyscripts/schema.pymain2200%
src/lyscripts/schema.py(no function)191095%
src/lyscripts/utils.pybinom_pmf61083%
src/lyscripts/utils.pyget_dict_depth700100%
src/lyscripts/utils.pydelete_private_keys700100%
src/lyscripts/utils.pyflatten800100%
src/lyscripts/utils.pyunflatten700100%
src/lyscripts/utils.pyget_modalities_subset72071%
src/lyscripts/utils.pyload_patient_data500100%
src/lyscripts/utils.pyload_yaml_params400100%
src/lyscripts/utils.pyload_model_samples400100%
src/lyscripts/utils.pyget_hdf5_backend62067%
src/lyscripts/utils.py(no function)2300100%
Total 1551392075%
+

+ No items found using the specified filter. +

+

1 empty function skipped.

+
+ + + diff --git a/htmlcov/index.html b/htmlcov/index.html new file mode 100644 index 0000000..ccdc805 --- /dev/null +++ b/htmlcov/index.html @@ -0,0 +1,300 @@ + + + + + Coverage report + + + + + +
+
+

Coverage report: + 75% +

+ +
+ +
+ + +
+
+

+ Files + Functions + Classes +

+

+ coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Filestatementsmissingexcludedcoverage
src/lyscripts/__init__.py347079%
src/lyscripts/__main__.py3300%
src/lyscripts/_version.py133077%
src/lyscripts/cli.py2612054%
src/lyscripts/compute/__init__.py91089%
src/lyscripts/compute/__main__.py5500%
src/lyscripts/compute/posteriors.py4619059%
src/lyscripts/compute/prevalences.py807091%
src/lyscripts/compute/priors.py352094%
src/lyscripts/compute/risks.py5133035%
src/lyscripts/compute/utils.py1206095%
src/lyscripts/configs.py25527089%
src/lyscripts/data/__init__.py121092%
src/lyscripts/data/__main__.py181800%
src/lyscripts/data/enhance.py248067%
src/lyscripts/data/filter.py4930039%
src/lyscripts/data/generate.py394090%
src/lyscripts/data/join.py209055%
src/lyscripts/data/lyproxify.py12167045%
src/lyscripts/data/split.py3014053%
src/lyscripts/data/utils.py900100%
src/lyscripts/decorators.py414090%
src/lyscripts/evaluate.py7557024%
src/lyscripts/plots.py16623086%
src/lyscripts/sample.py13611092%
src/lyscripts/schedule.py2913055%
src/lyscripts/schema.py213086%
src/lyscripts/utils.py845094%
Total1551392075%
+

+ No items found using the specified filter. +

+
+ + + diff --git a/htmlcov/keybd_closed_cb_ce680311.png b/htmlcov/keybd_closed_cb_ce680311.png new file mode 100644 index 0000000000000000000000000000000000000000..ba119c47df81ed2bbd27a06988abf700139c4f99 GIT binary patch literal 9004 zcmeHLc{tSF+aIY=A^R4_poB4tZAN2XC;O7M(inrW3}(h&Q4}dl*&-65$i9^&vW6_# zcM4g`Qix=GhkBl;=lwnJ@Ap2}^}hc-b6vBXb3XUyzR%~}_c`-Dw+!?&>5p(90RRB> zXe~7($~PP3eT?=X<@3~Q1w84vX~IoSx~1#~02+TopXK(db;4v6!{+W`RHLkkHO zo;+s?)puc`+$yOwHv>I$5^8v^F3<|$44HA8AFnFB0cAP|C`p}aSMJK*-CUB{eQ!;K z-9Ju3OQ+xVPr3P#o4>_lNBT;M+1vgV&B~6!naOGHb-LFA9TkfHv1IFA1Y!Iz!Zl3) z%c#-^zNWPq7U_}6I7aHSmFWi125RZrNBKyvnV^?64)zviS;E!UD%LaGRl6@zn!3E{ zJ`B$5``cH_3a)t1#6I7d==JeB_IcSU%=I#DrRCBGm8GvCmA=+XHEvC2SIfsNa0(h9 z7P^C4U`W@@`9p>2f^zyb5B=lpc*RZMn-%%IqrxSWQF8{ec3i?-AB(_IVe z)XgT>Y^u41MwOMFvU=I4?!^#jaS-%bjnx@ zmL44yVEslR_ynm18F!u}Ru#moEn3EE?1=9@$B1Z5aLi5b8{&?V(IAYBzIar!SiY3< z`l0V)djHtrImy}(!7x-Pmq+njM)JFQ9mx*(C+9a3M)(_SW|lrN=gfxFhStu^zvynS zm@gl;>d8i8wpUkX42vS3BEzE3-yctH%t0#N%s+6-&_<*Fe7+h=`=FM?DOg1)eGL~~ zQvIFm$D*lqEh07XrXY=jb%hdyP4)`wyMCb$=-z9(lOme9=tirVkb)_GOl2MJn;=Ky z^0pV1owR7KP-BSxhI@@@+gG0roD-kXE1;!#R7KY1QiUbyDdTElm|ul7{mMdF1%UDJ z_vp=Vo!TCF?D*?u% zk~}4!xK2MSQd-QKC0${G=ZRv2x8%8ZqdfR!?Dv=5Mj^8WU)?iH;C?o6rSQy*^YwQb zf@5V)q=xah#a3UEIBC~N7on(p4jQd4K$|i7k`d8mw|M{Mxapl46Z^X^9U}JgqH#;T z`CTzafpMD+J-LjzF+3Xau>xM_sXisRj6m-287~i9g|%gHc}v77>n_+p7ZgmJszx!b zSmL4wV;&*5Z|zaCk`rOYFdOjZLLQr!WSV6AlaqYh_OE)>rYdtx`gk$yAMO=-E1b~J zIZY6gM*}1UWsJ)TW(pf1=h?lJy_0TFOr|nALGW>$IE1E7z+$`^2WJY+>$$nJo8Rs` z)xS>AH{N~X3+b=2+8Q_|n(1JoGv55r>TuwBV~MXE&9?3Zw>cIxnOPNs#gh~C4Zo=k z&!s;5)^6UG>!`?hh0Q|r|Qbm>}pgtOt23Vh!NSibozH$`#LSiYL)HR4bkfEJMa zBHwC3TaHx|BzD|MXAr>mm&FbZXeEX-=W}Ji&!pji4sO$#0Wk^Q7j%{8#bJPn$C=E% zPlB}0)@Ti^r_HMJrTMN?9~4LQbIiUiOKBVNm_QjABKY4;zC88yVjvB>ZETNzr%^(~ zI3U&Ont?P`r&4 z#Bp)jcVV_N_{c1_qW}_`dQm)D`NG?h{+S!YOaUgWna4i8SuoLcXAZ|#Jh&GNn7B}3 z?vZ8I{LpmCYT=@6)dLPd@|(;d<08ufov%+V?$mgUYQHYTrc%eA=CDUzK}v|G&9}yJ z)|g*=+RH1IQ>rvkY9UIam=fkxWDyGIKQ2RU{GqOQjD8nG#sl+$V=?wpzJdT=wlNWr z1%lw&+;kVs(z?e=YRWRA&jc75rQ~({*TS<( z8X!j>B}?Bxrrp%wEE7yBefQ?*nM20~+ZoQK(NO_wA`RNhsqVkXHy|sod@mqen=B#@ zmLi=x2*o9rWqTMWoB&qdZph$~qkJJTVNc*8^hU?gH_fY{GYPEBE8Q{j0Y$tvjMv%3 z)j#EyBf^7n)2d8IXDYX2O0S%ZTnGhg4Ss#sEIATKpE_E4TU=GimrD5F6K(%*+T-!o z?Se7^Vm`$ZKDwq+=~jf?w0qC$Kr&R-;IF#{iLF*8zKu8(=#chRO;>x zdM;h{i{RLpJgS!B-ueTFs8&4U4+D8|7nP~UZ@P`J;*0sj^#f_WqT#xpA?@qHonGB& zQ<^;OLtOG1w#)N~&@b0caUL7syAsAxV#R`n>-+eVL9aZwnlklzE>-6!1#!tVA`uNo z>Gv^P)sohc~g_1YMC;^f(N<{2y5C^;QCEXo;LQ^#$0 zr>jCrdoeXuff!dJ^`#=Wy2Gumo^Qt7BZrI~G+Pyl_kL>is3P0^JlE;Sjm-YfF~I>t z_KeNpK|5U&F4;v?WS&#l(jxUWDarfcIcl=-6!8>^S`57!M6;hZea5IFA@)2+*Rt85 zi-MBs_b^DU8LygXXQGkG+86N7<%M|baM(orG*ASffC`p!?@m{qd}IcYmZyi^d}#Q& zNjk-0@CajpUI-gPm20ERVDO!L8@p`tMJ69FD(ASIkdoLdiRV6h9TPKRz>2WK4upHd z6OZK33EP?`GoJkXh)S035}uLUO$;TlXwNdMg-WOhLB)7a`-%*a9lFmjf6n+4ZmIHN z-V@$ z8PXsoR4*`5RwXz=A8|5;aXKtSHFccj%dG7cO~UBJnt)61K>-uPX)`vu{7fcX6_>zZ zw_2V&Li+7mxbf!f7{Rk&VVyY!UtZywac%g!cH+xh#j$a`uf?XWl<``t`36W;p7=_* zO6uf~2{sAdkZn=Ts@p0>8N8rzw2ZLS@$ibV-c-QmG@%|3gUUrRxu=e*ekhTa+f?8q z3$JVGPr9w$VQG~QCq~Y=2ThLIH!T@(>{NihJ6nj*HA_C#Popv)CBa)+UI-bx8u8zfCT^*1|k z&N9oFYsZEijPn31Yx_yO5pFs>0tOAV=oRx~Wpy5ie&S_449m4R^{LWQMA~}vocV1O zIf#1ZV85E>tvZE4mz~zn{hs!pkIQM;EvZMimqiPAJu-9P@mId&nb$lsrICS=)zU3~ zn>a#9>}5*3N)9;PTMZ)$`5k} z?iG}Rwj$>Y*|(D3S3e&fxhaPHma8@vwu(cwdlaCjX+NIK6=$H4U`rfzcWQVOhp{fnzuZhgCCGpw|p zTi`>cv~xVzdx|^`C0vXdlMwPae3S?>3|7v$e*Bs6-5gS>>FMHk_r2M(ADOV{KV7+6 zA@5Q(mdx%7J}MY}K461iuQ}5GwDGI=Yc&g0MZHu)7gC3{5@QZj6SJl*o0MS2Cl_ia zyK?9QmC9tJ6yn{EA-erJ4wk$+!E#X(s~9h^HOmQ_|6V_s1)k;%9Q6Niw}SyT?jxl4 z;HYz2$Nj$8Q_*Xo`TWEUx^Q9b+ik@$o39`mlY&P}G8wnjdE+Dlj?uL;$aB$n;x zWoh-M_u>9}_Ok@d_uidMqz10zJc}RQijPW3Fs&~1am=j*+A$QWTvxf9)6n;n8zTQW z!Q_J1%apTsJzLF`#^P_#mRv2Ya_keUE7iMSP!ha-WQoo0vZZG?gyR;+4q8F6tL#u< zRj8Hu5f-p1$J;)4?WpGL{4@HmJ6&tF9A5Tc8Trp>;Y>{^s?Q1&bam}?OjsnKd?|Z82aix26wUOLxbEW~E)|CgJ#)MLf_me# zv4?F$o@A~Um)6>HlM0=3Bd-vc91EM}D+t6-@!}O%i*&Wl%@#C8X+?5+nv`oPu!!=5 znbL+Fk_#J_%8vOq^FIv~5N(nk03kyo1p@l|1c+rO^zCG3bk2?|%AF;*|4si1XM<`a z1NY0-8$wv?&129!(g_A1lXR!+pD*1*cF?T~e1d6*G1Fz)jcSaZoKpxtA%FNnKP2jo zLXn@OR#1z@6zuH%mMB98}-t zHJqClsZ!G5xMSgIs_=<8sBePXxfoXsuvy`|buON9BX%s-o>OVLA)k3W=wKnw1?so$ zEjm0aS=zu@Xu#;{A)QTjJ$a9_={++ACkRY*sk3jLk&Fu}RxR<-DXR<`5`$VNG*wJE zidM6VzaQ!M0gbQM98@x@;#0qUS8O)p6mrYwTk*;8J~!ovbY6jon^Ki}uggd3#J5G8 z>awvtF85Y<9yE{Iag}J7O7)1O=ylk^255@XmV5J06-{xaaSNASZoTKKp~$tSxdUI~ zU1RZ&UuW37Ro&_ryj^cSt$Jd&pt|+h!A&dwcr&`S=R5E`=6Tm`+(qGm@$YZ8(8@a$ zXfo@Rwtvm7N3RMmVCb7radAs-@QtCXx^CQ-<)V>QPLZy@jH{#dc4#(y zV)6Hp{ZMz!|NG8!>i01gZMy)G<8Hf2X7e&LH_gOaajW<<^Xi55@OnlY*|S|*TS8;u_nHbv7lgmmZ+Q<5 zi!*lLCJmdpyzl(L${$C?(pVo|oR%r~x_B_ocPePa_);27^=n4L=`toZ;xdBut9rSv z?wDQ7j2I3WQBdhz%X7`2YaG_y|wA!7|s?k;A&WNMLMTZEzCaE^d??E&u?f=ejQBR~|< z)=thyP2(p8r6mt?Ad}tXAP_GvF9|P630I;$1cpQ+Ay7C34hK^ZV3H4kjPV8&NP>G5 zKRDEIBrFl{M#j4mfP0)68&?mqJP1S?2mU0djAGTjDV;wZ?6vplNn~3Hn$nP>%!dMi zz@bnC7zzi&k&s{QDWkf&zgrVXKUJjY3Gv3bL0}S4h>OdgEJ$Q^&p-VAr3J}^a*+rz z!jW7(h*+GuCyqcC{MD(Ovj^!{pB^OKUe|uy&bD?CN>KZrf3?v>>l*xSvnQiH-o^ViN$%FRdm9url;%(*jf5H$*S)8;i0xWHdl>$p);nH9v0)YfW?Vz$! zNCeUbi9`NEg(i^57y=fzM@1o*z*Bf6?QCV>2p9}(BLlYsOCfMjFv1pw1mlo)Py{8v zppw{MDfEeWN+n>Ne~oI7%9cU}mz0r3!es2gNF0t5jkGipjIo2lz;-e)7}Ul_#!eDv zw;#>kI>;#-pyfeu3Fsd^2F@6=oh#8r9;A!G0`-mm7%{=S;Ec(bJ=I_`FodKGQVNEY zmXwr4{9*jpDl%4{ggQZ5Ac z%wYTdl*!1c5^)%^E78Q&)ma|27c6j(a=)g4sGrp$r{jv>>M2 z6y)E5|Aooe!PSfKzvKA>`a6pfK3=E8vL14ksP&f=>gOP?}rG6ye@9ZR3 zJF*vsh*P$w390i!FV~~_Hv6t2Zl<4VUi|rNja#boFt{%q~xGb z(2petq9A*_>~B*>?d?Olx^lmYg4)}sH2>G42RE; literal 0 HcmV?d00001 diff --git a/htmlcov/status.json b/htmlcov/status.json new file mode 100644 index 0000000..232ff31 --- /dev/null +++ b/htmlcov/status.json @@ -0,0 +1 @@ +{"note":"This file is an internal implementation detail to speed up HTML report generation. Its format can change at any time. You might be looking for the JSON report: https://coverage.rtfd.io/cmd.html#cmd-json","format":5,"version":"7.9.1","globals":"78e84f760f4a15b01f0493820b8aab4c","files":{"z_5bf5c588c698c6cc___init___py":{"hash":"cd9cf9aa912f02155af58c7537c296f8","index":{"url":"z_5bf5c588c698c6cc___init___py.html","file":"src/lyscripts/__init__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":34,"n_excluded":0,"n_missing":7,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_5bf5c588c698c6cc___main___py":{"hash":"688ae147ef12b10ab9787478138c52da","index":{"url":"z_5bf5c588c698c6cc___main___py.html","file":"src/lyscripts/__main__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":3,"n_excluded":0,"n_missing":3,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_5bf5c588c698c6cc__version_py":{"hash":"8d0943fd619368a6838316fdbe9bf82a","index":{"url":"z_5bf5c588c698c6cc__version_py.html","file":"src/lyscripts/_version.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":13,"n_excluded":0,"n_missing":3,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_5bf5c588c698c6cc_cli_py":{"hash":"b9105b2f4782eea0c4c7357613d2dfa7","index":{"url":"z_5bf5c588c698c6cc_cli_py.html","file":"src/lyscripts/cli.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":26,"n_excluded":0,"n_missing":12,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_055061514423972c___init___py":{"hash":"4587c7447681dd0a28dee41eca8fd090","index":{"url":"z_055061514423972c___init___py.html","file":"src/lyscripts/compute/__init__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":9,"n_excluded":0,"n_missing":1,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_055061514423972c___main___py":{"hash":"6a0bdc66902725a1720ac3d75db6e969","index":{"url":"z_055061514423972c___main___py.html","file":"src/lyscripts/compute/__main__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":5,"n_excluded":0,"n_missing":5,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_055061514423972c_posteriors_py":{"hash":"369f3d9010aa72b2bd34bc161fe01025","index":{"url":"z_055061514423972c_posteriors_py.html","file":"src/lyscripts/compute/posteriors.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":46,"n_excluded":0,"n_missing":19,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_055061514423972c_prevalences_py":{"hash":"b0cbdf81221c8f32ec27191c706f6c50","index":{"url":"z_055061514423972c_prevalences_py.html","file":"src/lyscripts/compute/prevalences.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":80,"n_excluded":0,"n_missing":7,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_055061514423972c_priors_py":{"hash":"c9925520e21e1710ca9171c6770c3e20","index":{"url":"z_055061514423972c_priors_py.html","file":"src/lyscripts/compute/priors.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":35,"n_excluded":0,"n_missing":2,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_055061514423972c_risks_py":{"hash":"a754c2897e9a0bdd2e69b96b45dbd486","index":{"url":"z_055061514423972c_risks_py.html","file":"src/lyscripts/compute/risks.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":51,"n_excluded":0,"n_missing":33,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_055061514423972c_utils_py":{"hash":"5d1481ec413fa3e3564577c174854a96","index":{"url":"z_055061514423972c_utils_py.html","file":"src/lyscripts/compute/utils.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":120,"n_excluded":0,"n_missing":6,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_5bf5c588c698c6cc_configs_py":{"hash":"1603a9ead1b54855e0054e4a88aeea3b","index":{"url":"z_5bf5c588c698c6cc_configs_py.html","file":"src/lyscripts/configs.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":255,"n_excluded":0,"n_missing":27,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_9b7bcb970ba14d6a___init___py":{"hash":"e6ebf387a32b452c0b132db1bc40f4dc","index":{"url":"z_9b7bcb970ba14d6a___init___py.html","file":"src/lyscripts/data/__init__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":12,"n_excluded":0,"n_missing":1,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_9b7bcb970ba14d6a___main___py":{"hash":"6f0c2597cfa98ee3fadd28928f0b59a9","index":{"url":"z_9b7bcb970ba14d6a___main___py.html","file":"src/lyscripts/data/__main__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":18,"n_excluded":0,"n_missing":18,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_9b7bcb970ba14d6a_enhance_py":{"hash":"daaae3cc10335b73cc4cd13a6649adf5","index":{"url":"z_9b7bcb970ba14d6a_enhance_py.html","file":"src/lyscripts/data/enhance.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":24,"n_excluded":0,"n_missing":8,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_9b7bcb970ba14d6a_filter_py":{"hash":"302cfef0c03c9c928241037432629697","index":{"url":"z_9b7bcb970ba14d6a_filter_py.html","file":"src/lyscripts/data/filter.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":49,"n_excluded":0,"n_missing":30,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_9b7bcb970ba14d6a_generate_py":{"hash":"5f82e5dfa2ada81bfe6a3c4fe1e56c0e","index":{"url":"z_9b7bcb970ba14d6a_generate_py.html","file":"src/lyscripts/data/generate.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":39,"n_excluded":0,"n_missing":4,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_9b7bcb970ba14d6a_join_py":{"hash":"d5ae1efd4c338a18cb81aff4cf26f3cd","index":{"url":"z_9b7bcb970ba14d6a_join_py.html","file":"src/lyscripts/data/join.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":20,"n_excluded":0,"n_missing":9,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_9b7bcb970ba14d6a_lyproxify_py":{"hash":"28bce4df322af2c94ae8d9fd2d4ea088","index":{"url":"z_9b7bcb970ba14d6a_lyproxify_py.html","file":"src/lyscripts/data/lyproxify.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":121,"n_excluded":0,"n_missing":67,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_9b7bcb970ba14d6a_split_py":{"hash":"bc8f8c55ce94e7faf55afa156977968b","index":{"url":"z_9b7bcb970ba14d6a_split_py.html","file":"src/lyscripts/data/split.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":30,"n_excluded":0,"n_missing":14,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_9b7bcb970ba14d6a_utils_py":{"hash":"69c2607314172ebe2d9aae816b2846a3","index":{"url":"z_9b7bcb970ba14d6a_utils_py.html","file":"src/lyscripts/data/utils.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":9,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_5bf5c588c698c6cc_decorators_py":{"hash":"ab992d78a550f290f0a15fd360bd6868","index":{"url":"z_5bf5c588c698c6cc_decorators_py.html","file":"src/lyscripts/decorators.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":41,"n_excluded":0,"n_missing":4,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_5bf5c588c698c6cc_evaluate_py":{"hash":"feb4d5f70d877520af63e2ffc1bb7beb","index":{"url":"z_5bf5c588c698c6cc_evaluate_py.html","file":"src/lyscripts/evaluate.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":75,"n_excluded":0,"n_missing":57,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_5bf5c588c698c6cc_plots_py":{"hash":"0b5c3adc29ddbba1145ad27d826f98eb","index":{"url":"z_5bf5c588c698c6cc_plots_py.html","file":"src/lyscripts/plots.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":166,"n_excluded":0,"n_missing":23,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_5bf5c588c698c6cc_sample_py":{"hash":"7f2875a7dbb5c94328f9325e0656c871","index":{"url":"z_5bf5c588c698c6cc_sample_py.html","file":"src/lyscripts/sample.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":136,"n_excluded":0,"n_missing":11,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_5bf5c588c698c6cc_schedule_py":{"hash":"240eec11df40be8426b5201a24be2ddd","index":{"url":"z_5bf5c588c698c6cc_schedule_py.html","file":"src/lyscripts/schedule.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":29,"n_excluded":0,"n_missing":13,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_5bf5c588c698c6cc_schema_py":{"hash":"abe23b86d4cae3c39895b659c8a8552e","index":{"url":"z_5bf5c588c698c6cc_schema_py.html","file":"src/lyscripts/schema.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":21,"n_excluded":0,"n_missing":3,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_5bf5c588c698c6cc_utils_py":{"hash":"523f50924333299a9638fc5393a1b12d","index":{"url":"z_5bf5c588c698c6cc_utils_py.html","file":"src/lyscripts/utils.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":84,"n_excluded":0,"n_missing":5,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}}}} \ No newline at end of file diff --git a/htmlcov/style_cb_81f8c14c.css b/htmlcov/style_cb_81f8c14c.css new file mode 100644 index 0000000..e54e87a --- /dev/null +++ b/htmlcov/style_cb_81f8c14c.css @@ -0,0 +1,337 @@ +@charset "UTF-8"; +/* Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 */ +/* For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt */ +/* Don't edit this .css file. Edit the .scss file instead! */ +html, body, h1, h2, h3, p, table, td, th { margin: 0; padding: 0; border: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; } + +body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 1em; background: #fff; color: #000; } + +@media (prefers-color-scheme: dark) { body { background: #1e1e1e; } } + +@media (prefers-color-scheme: dark) { body { color: #eee; } } + +html > body { font-size: 16px; } + +a:active, a:focus { outline: 2px dashed #007acc; } + +p { font-size: .875em; line-height: 1.4em; } + +table { border-collapse: collapse; } + +td { vertical-align: top; } + +table tr.hidden { display: none !important; } + +p#no_rows { display: none; font-size: 1.15em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; } + +a.nav { text-decoration: none; color: inherit; } + +a.nav:hover { text-decoration: underline; color: inherit; } + +.hidden { display: none; } + +header { background: #f8f8f8; width: 100%; z-index: 2; border-bottom: 1px solid #ccc; } + +@media (prefers-color-scheme: dark) { header { background: black; } } + +@media (prefers-color-scheme: dark) { header { border-color: #333; } } + +header .content { padding: 1rem 3.5rem; } + +header h2 { margin-top: .5em; font-size: 1em; } + +header h2 a.button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; background: #eee; color: inherit; text-decoration: none; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; } + +@media (prefers-color-scheme: dark) { header h2 a.button { background: #333; } } + +@media (prefers-color-scheme: dark) { header h2 a.button { border-color: #444; } } + +header h2 a.button.current { border: 2px solid; background: #fff; border-color: #999; cursor: default; } + +@media (prefers-color-scheme: dark) { header h2 a.button.current { background: #1e1e1e; } } + +@media (prefers-color-scheme: dark) { header h2 a.button.current { border-color: #777; } } + +header p.text { margin: .5em 0 -.5em; color: #666; font-style: italic; } + +@media (prefers-color-scheme: dark) { header p.text { color: #aaa; } } + +header.sticky { position: fixed; left: 0; right: 0; height: 2.5em; } + +header.sticky .text { display: none; } + +header.sticky h1, header.sticky h2 { font-size: 1em; margin-top: 0; display: inline-block; } + +header.sticky .content { padding: 0.5rem 3.5rem; } + +header.sticky .content p { font-size: 1em; } + +header.sticky ~ #source { padding-top: 6.5em; } + +main { position: relative; z-index: 1; } + +footer { margin: 1rem 3.5rem; } + +footer .content { padding: 0; color: #666; font-style: italic; } + +@media (prefers-color-scheme: dark) { footer .content { color: #aaa; } } + +#index { margin: 1rem 0 0 3.5rem; } + +h1 { font-size: 1.25em; display: inline-block; } + +#filter_container { float: right; margin: 0 2em 0 0; line-height: 1.66em; } + +#filter_container #filter { width: 10em; padding: 0.2em 0.5em; border: 2px solid #ccc; background: #fff; color: #000; } + +@media (prefers-color-scheme: dark) { #filter_container #filter { border-color: #444; } } + +@media (prefers-color-scheme: dark) { #filter_container #filter { background: #1e1e1e; } } + +@media (prefers-color-scheme: dark) { #filter_container #filter { color: #eee; } } + +#filter_container #filter:focus { border-color: #007acc; } + +#filter_container :disabled ~ label { color: #ccc; } + +@media (prefers-color-scheme: dark) { #filter_container :disabled ~ label { color: #444; } } + +#filter_container label { font-size: .875em; color: #666; } + +@media (prefers-color-scheme: dark) { #filter_container label { color: #aaa; } } + +header button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; background: #eee; color: inherit; text-decoration: none; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; } + +@media (prefers-color-scheme: dark) { header button { background: #333; } } + +@media (prefers-color-scheme: dark) { header button { border-color: #444; } } + +header button:active, header button:focus { outline: 2px dashed #007acc; } + +header button.run { background: #eeffee; } + +@media (prefers-color-scheme: dark) { header button.run { background: #373d29; } } + +header button.run.show_run { background: #dfd; border: 2px solid #00dd00; margin: 0 .1em; } + +@media (prefers-color-scheme: dark) { header button.run.show_run { background: #373d29; } } + +header button.mis { background: #ffeeee; } + +@media (prefers-color-scheme: dark) { header button.mis { background: #4b1818; } } + +header button.mis.show_mis { background: #fdd; border: 2px solid #ff0000; margin: 0 .1em; } + +@media (prefers-color-scheme: dark) { header button.mis.show_mis { background: #4b1818; } } + +header button.exc { background: #f7f7f7; } + +@media (prefers-color-scheme: dark) { header button.exc { background: #333; } } + +header button.exc.show_exc { background: #eee; border: 2px solid #808080; margin: 0 .1em; } + +@media (prefers-color-scheme: dark) { header button.exc.show_exc { background: #333; } } + +header button.par { background: #ffffd5; } + +@media (prefers-color-scheme: dark) { header button.par { background: #650; } } + +header button.par.show_par { background: #ffa; border: 2px solid #bbbb00; margin: 0 .1em; } + +@media (prefers-color-scheme: dark) { header button.par.show_par { background: #650; } } + +#help_panel, #source p .annotate.long { display: none; position: absolute; z-index: 999; background: #ffffcc; border: 1px solid #888; border-radius: .2em; color: #333; padding: .25em .5em; } + +#source p .annotate.long { white-space: normal; float: right; top: 1.75em; right: 1em; height: auto; } + +#help_panel_wrapper { float: right; position: relative; } + +#keyboard_icon { margin: 5px; } + +#help_panel_state { display: none; } + +#help_panel { top: 25px; right: 0; padding: .75em; border: 1px solid #883; color: #333; } + +#help_panel .keyhelp p { margin-top: .75em; } + +#help_panel .legend { font-style: italic; margin-bottom: 1em; } + +.indexfile #help_panel { width: 25em; } + +.pyfile #help_panel { width: 18em; } + +#help_panel_state:checked ~ #help_panel { display: block; } + +kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em .35em; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-weight: bold; background: #eee; border-radius: 3px; } + +#source { padding: 1em 0 1em 3.5rem; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; } + +#source p { position: relative; white-space: pre; } + +#source p * { box-sizing: border-box; } + +#source p .n { float: left; text-align: right; width: 3.5rem; box-sizing: border-box; margin-left: -3.5rem; padding-right: 1em; color: #999; user-select: none; } + +@media (prefers-color-scheme: dark) { #source p .n { color: #777; } } + +#source p .n.highlight { background: #ffdd00; } + +#source p .n a { scroll-margin-top: 6em; text-decoration: none; color: #999; } + +@media (prefers-color-scheme: dark) { #source p .n a { color: #777; } } + +#source p .n a:hover { text-decoration: underline; color: #999; } + +@media (prefers-color-scheme: dark) { #source p .n a:hover { color: #777; } } + +#source p .t { display: inline-block; width: 100%; box-sizing: border-box; margin-left: -.5em; padding-left: 0.3em; border-left: 0.2em solid #fff; } + +@media (prefers-color-scheme: dark) { #source p .t { border-color: #1e1e1e; } } + +#source p .t:hover { background: #f2f2f2; } + +@media (prefers-color-scheme: dark) { #source p .t:hover { background: #282828; } } + +#source p .t:hover ~ .r .annotate.long { display: block; } + +#source p .t .com { color: #008000; font-style: italic; line-height: 1px; } + +@media (prefers-color-scheme: dark) { #source p .t .com { color: #6a9955; } } + +#source p .t .key { font-weight: bold; line-height: 1px; } + +#source p .t .str, #source p .t .fst { color: #0451a5; } + +@media (prefers-color-scheme: dark) { #source p .t .str, #source p .t .fst { color: #9cdcfe; } } + +#source p.mis .t { border-left: 0.2em solid #ff0000; } + +#source p.mis.show_mis .t { background: #fdd; } + +@media (prefers-color-scheme: dark) { #source p.mis.show_mis .t { background: #4b1818; } } + +#source p.mis.show_mis .t:hover { background: #f2d2d2; } + +@media (prefers-color-scheme: dark) { #source p.mis.show_mis .t:hover { background: #532323; } } + +#source p.run .t { border-left: 0.2em solid #00dd00; } + +#source p.run.show_run .t { background: #dfd; } + +@media (prefers-color-scheme: dark) { #source p.run.show_run .t { background: #373d29; } } + +#source p.run.show_run .t:hover { background: #d2f2d2; } + +@media (prefers-color-scheme: dark) { #source p.run.show_run .t:hover { background: #404633; } } + +#source p.exc .t { border-left: 0.2em solid #808080; } + +#source p.exc.show_exc .t { background: #eee; } + +@media (prefers-color-scheme: dark) { #source p.exc.show_exc .t { background: #333; } } + +#source p.exc.show_exc .t:hover { background: #e2e2e2; } + +@media (prefers-color-scheme: dark) { #source p.exc.show_exc .t:hover { background: #3c3c3c; } } + +#source p.par .t { border-left: 0.2em solid #bbbb00; } + +#source p.par.show_par .t { background: #ffa; } + +@media (prefers-color-scheme: dark) { #source p.par.show_par .t { background: #650; } } + +#source p.par.show_par .t:hover { background: #f2f2a2; } + +@media (prefers-color-scheme: dark) { #source p.par.show_par .t:hover { background: #6d5d0c; } } + +#source p .r { position: absolute; top: 0; right: 2.5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; } + +#source p .annotate { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; color: #666; padding-right: .5em; } + +@media (prefers-color-scheme: dark) { #source p .annotate { color: #ddd; } } + +#source p .annotate.short:hover ~ .long { display: block; } + +#source p .annotate.long { width: 30em; right: 2.5em; } + +#source p input { display: none; } + +#source p input ~ .r label.ctx { cursor: pointer; border-radius: .25em; } + +#source p input ~ .r label.ctx::before { content: "â–¶ "; } + +#source p input ~ .r label.ctx:hover { background: #e8f4ff; color: #666; } + +@media (prefers-color-scheme: dark) { #source p input ~ .r label.ctx:hover { background: #0f3a42; } } + +@media (prefers-color-scheme: dark) { #source p input ~ .r label.ctx:hover { color: #aaa; } } + +#source p input:checked ~ .r label.ctx { background: #d0e8ff; color: #666; border-radius: .75em .75em 0 0; padding: 0 .5em; margin: -.25em 0; } + +@media (prefers-color-scheme: dark) { #source p input:checked ~ .r label.ctx { background: #056; } } + +@media (prefers-color-scheme: dark) { #source p input:checked ~ .r label.ctx { color: #aaa; } } + +#source p input:checked ~ .r label.ctx::before { content: "â–¼ "; } + +#source p input:checked ~ .ctxs { padding: .25em .5em; overflow-y: scroll; max-height: 10.5em; } + +#source p label.ctx { color: #999; display: inline-block; padding: 0 .5em; font-size: .8333em; } + +@media (prefers-color-scheme: dark) { #source p label.ctx { color: #777; } } + +#source p .ctxs { display: block; max-height: 0; overflow-y: hidden; transition: all .2s; padding: 0 .5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; white-space: nowrap; background: #d0e8ff; border-radius: .25em; margin-right: 1.75em; text-align: right; } + +@media (prefers-color-scheme: dark) { #source p .ctxs { background: #056; } } + +#index { font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 0.875em; } + +#index table.index { margin-left: -.5em; } + +#index td, #index th { text-align: right; padding: .25em .5em; border-bottom: 1px solid #eee; } + +@media (prefers-color-scheme: dark) { #index td, #index th { border-color: #333; } } + +#index td.name, #index th.name { text-align: left; width: auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; min-width: 15em; } + +#index th { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-style: italic; color: #333; cursor: pointer; } + +@media (prefers-color-scheme: dark) { #index th { color: #ddd; } } + +#index th:hover { background: #eee; } + +@media (prefers-color-scheme: dark) { #index th:hover { background: #333; } } + +#index th .arrows { color: #666; font-size: 85%; font-family: sans-serif; font-style: normal; pointer-events: none; } + +#index th[aria-sort="ascending"], #index th[aria-sort="descending"] { white-space: nowrap; background: #eee; padding-left: .5em; } + +@media (prefers-color-scheme: dark) { #index th[aria-sort="ascending"], #index th[aria-sort="descending"] { background: #333; } } + +#index th[aria-sort="ascending"] .arrows::after { content: " â–²"; } + +#index th[aria-sort="descending"] .arrows::after { content: " â–¼"; } + +#index td.name { font-size: 1.15em; } + +#index td.name a { text-decoration: none; color: inherit; } + +#index td.name .no-noun { font-style: italic; } + +#index tr.total td, #index tr.total_dynamic td { font-weight: bold; border-top: 1px solid #ccc; border-bottom: none; } + +#index tr.region:hover { background: #eee; } + +@media (prefers-color-scheme: dark) { #index tr.region:hover { background: #333; } } + +#index tr.region:hover td.name { text-decoration: underline; color: inherit; } + +#scroll_marker { position: fixed; z-index: 3; right: 0; top: 0; width: 16px; height: 100%; background: #fff; border-left: 1px solid #eee; will-change: transform; } + +@media (prefers-color-scheme: dark) { #scroll_marker { background: #1e1e1e; } } + +@media (prefers-color-scheme: dark) { #scroll_marker { border-color: #333; } } + +#scroll_marker .marker { background: #ccc; position: absolute; min-height: 3px; width: 100%; } + +@media (prefers-color-scheme: dark) { #scroll_marker .marker { background: #444; } } diff --git a/htmlcov/z_055061514423972c___init___py.html b/htmlcov/z_055061514423972c___init___py.html new file mode 100644 index 0000000..b0c99dc --- /dev/null +++ b/htmlcov/z_055061514423972c___init___py.html @@ -0,0 +1,118 @@ + + + + + Coverage for src/lyscripts/compute/__init__.py: 89% + + + + + +
+
+

+ Coverage for src/lyscripts/compute/__init__.py: + 89% +

+ +

+ 9 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Commands to compute prior and posterior state distributions from model samples. 

+

2 

+

3This can in turn speed up the computation of risks and prevalences. 

+

4""" 

+

5 

+

6from pydantic_settings import BaseSettings, CliApp, CliSubCommand 

+

7 

+

8from lyscripts.compute import posteriors, prevalences, priors, risks 

+

9 

+

10 

+

11class ComputeCLI(BaseSettings): 

+

12 """Compute priors, posteriors, risks, and prevalences from model samples.""" 

+

13 

+

14 priors: CliSubCommand[priors.PriorsCLI] 

+

15 posteriors: CliSubCommand[posteriors.PosteriorsCLI] 

+

16 risks: CliSubCommand[risks.RisksCLI] 

+

17 prevalences: CliSubCommand[prevalences.PrevalencesCLI] 

+

18 

+

19 def cli_cmd(self) -> None: 

+

20 """Start the ``compute`` subcommand.""" 

+

21 CliApp.run_subcommand(self) 

+
+ + + diff --git a/htmlcov/z_055061514423972c___main___py.html b/htmlcov/z_055061514423972c___main___py.html new file mode 100644 index 0000000..fa31306 --- /dev/null +++ b/htmlcov/z_055061514423972c___main___py.html @@ -0,0 +1,105 @@ + + + + + Coverage for src/lyscripts/compute/__main__.py: 0% + + + + + +
+
+

+ Coverage for src/lyscripts/compute/__main__.py: + 0% +

+ +

+ 5 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Run the compute module as a script.""" 

+

2 

+

3from lyscripts.cli import assemble_main 

+

4from lyscripts.compute import ComputeCLI 

+

5 

+

6if __name__ == "__main__": 

+

7 main = assemble_main(settings_cls=ComputeCLI, prog_name="compute") 

+

8 main() 

+
+ + + diff --git a/htmlcov/z_055061514423972c_posteriors_py.html b/htmlcov/z_055061514423972c_posteriors_py.html new file mode 100644 index 0000000..196b9b8 --- /dev/null +++ b/htmlcov/z_055061514423972c_posteriors_py.html @@ -0,0 +1,239 @@ + + + + + Coverage for src/lyscripts/compute/posteriors.py: 59% + + + + + +
+
+

+ Coverage for src/lyscripts/compute/posteriors.py: + 59% +

+ +

+ 46 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Compute posterior state distributions. 

+

2 

+

3The posteriors are computed from drawn samples for a list of defined scenarios. If 

+

4priors have already been computed from the samples and the ``--cache_dir`` argument 

+

5is the same as during that computation, the priors will automatically be loaded from 

+

6the cache. 

+

7""" 

+

8 

+

9from typing import Literal 

+

10 

+

11import numpy as np 

+

12from loguru import logger 

+

13from lymph import models 

+

14from pydantic import Field 

+

15from rich import progress 

+

16 

+

17from lyscripts.cli import assemble_main 

+

18from lyscripts.compute.priors import compute_priors 

+

19from lyscripts.compute.utils import BaseComputeCLI, HDF5FileStorage, get_cached 

+

20from lyscripts.configs import ( 

+

21 DistributionConfig, 

+

22 GraphConfig, 

+

23 ModalityConfig, 

+

24 ModelConfig, 

+

25 add_distributions, 

+

26 add_modalities, 

+

27 construct_model, 

+

28) 

+

29from lyscripts.utils import console 

+

30 

+

31 

+

32def compute_posteriors( 

+

33 model_config: ModelConfig, 

+

34 graph_config: GraphConfig, 

+

35 dist_configs: dict[str, DistributionConfig], 

+

36 modality_configs: dict[str, ModalityConfig], 

+

37 priors: np.ndarray, 

+

38 diagnosis: dict[Literal["ipsi", "contra"], dict], 

+

39 midext: bool | None = None, 

+

40 mode: Literal["HMM", "BN"] = "HMM", 

+

41 progress_desc: str = "Computing posteriors from priors", 

+

42) -> np.ndarray: 

+

43 """Compute posterior state distributions from ``priors``. 

+

44 

+

45 This calls the ``model`` method :py:meth:`~lymph.types.Model.posterior_state_dist` 

+

46 for each of the pre-computed ``priors``, given the specified ``diagnosis`` pattern. 

+

47 

+

48 For the :py:class:`~lymph.models.Midline` model, the ``midext`` argument can be 

+

49 used to specify whether the midline extension is present or not. 

+

50 """ 

+

51 model = construct_model(model_config, graph_config) 

+

52 model = add_distributions(model, dist_configs) 

+

53 model = add_modalities(model, modality_configs) 

+

54 posteriors = [] 

+

55 kwargs = {"midext": midext} if isinstance(model, models.Midline) else {} 

+

56 

+

57 if isinstance(model, models.Unilateral | models.HPVUnilateral): 

+

58 diagnosis = diagnosis.get("ipsi") 

+

59 

+

60 for prior in progress.track( 

+

61 sequence=priors, 

+

62 description=progress_desc, 

+

63 total=len(priors), 

+

64 console=console, 

+

65 ): 

+

66 posteriors.append( 

+

67 model.posterior_state_dist( 

+

68 given_state_dist=prior, 

+

69 given_diagnosis=diagnosis, 

+

70 mode=mode, 

+

71 **kwargs, 

+

72 ), 

+

73 ) 

+

74 

+

75 return np.stack(posteriors) 

+

76 

+

77 

+

78class PosteriorsCLI(BaseComputeCLI): 

+

79 """Compute posterior state distributions for different diagnosis scenarios.""" 

+

80 

+

81 modalities: dict[str, ModalityConfig] = Field( 

+

82 default={}, 

+

83 description=( 

+

84 "Maps names of diagnostic modalities to their specificity/sensitivity." 

+

85 ), 

+

86 ) 

+

87 posteriors: HDF5FileStorage = Field( 

+

88 description="Storage for the computed posteriors.", 

+

89 ) 

+

90 

+

91 def cli_cmd(self) -> None: 

+

92 """Start the ``posteriors`` subcommand. 

+

93 

+

94 This will compute the posterior state distributions, given a personalized 

+

95 diagnosis pattern, for each of the scenarios provided to the command. 

+

96 """ 

+

97 logger.debug(self.model_dump_json(indent=2)) 

+

98 

+

99 global_attrs = self.model_dump( 

+

100 include={"model", "graph", "distributions", "modalities"}, 

+

101 ) 

+

102 self.posteriors.set_attrs(attrs=global_attrs, dataset="/") 

+

103 

+

104 samples = self.sampling.load() 

+

105 cached_compute_priors = get_cached(compute_priors, self.cache_dir) 

+

106 cached_compute_posteriors = get_cached(compute_posteriors, self.cache_dir) 

+

107 num_scens = len(self.scenarios) 

+

108 

+

109 for i, scenario in enumerate(self.scenarios): 

+

110 _fields = {"t_stages", "t_stages_dist", "mode"} 

+

111 prior_kwargs = scenario.model_dump(include=_fields) 

+

112 

+

113 _priors = cached_compute_priors( 

+

114 model_config=self.model, 

+

115 graph_config=self.graph, 

+

116 dist_configs=self.distributions, 

+

117 samples=samples, 

+

118 progress_desc=f"Computing priors for scenario {i + 1}/{num_scens}", 

+

119 **prior_kwargs, 

+

120 ) 

+

121 

+

122 _fields = {"diagnosis", "midext", "mode"} 

+

123 posterior_kwargs = scenario.model_dump(include=_fields) 

+

124 

+

125 posteriors = cached_compute_posteriors( 

+

126 model_config=self.model, 

+

127 graph_config=self.graph, 

+

128 dist_configs=self.distributions, 

+

129 modality_configs=self.modalities, 

+

130 priors=_priors, 

+

131 progress_desc=f"Computing posteriors for scenario {i + 1}/{num_scens}", 

+

132 **posterior_kwargs, 

+

133 ) 

+

134 

+

135 self.posteriors.save(values=posteriors, dataset=f"{i:03d}") 

+

136 self.posteriors.set_attrs(attrs=prior_kwargs, dataset=f"{i:03d}") 

+

137 self.posteriors.set_attrs(attrs=posterior_kwargs, dataset=f"{i:03d}") 

+

138 

+

139 

+

140if __name__ == "__main__": 

+

141 main = assemble_main(settings_cls=PosteriorsCLI, prog_name="compute posteriors") 

+

142 main() 

+
+ + + diff --git a/htmlcov/z_055061514423972c_prevalences_py.html b/htmlcov/z_055061514423972c_prevalences_py.html new file mode 100644 index 0000000..51f0c9e --- /dev/null +++ b/htmlcov/z_055061514423972c_prevalences_py.html @@ -0,0 +1,330 @@ + + + + + Coverage for src/lyscripts/compute/prevalences.py: 91% + + + + + +
+
+

+ Coverage for src/lyscripts/compute/prevalences.py: + 91% +

+ +

+ 80 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Prevalence prediction module. 

+

2 

+

3This computes the prevalence of an observed involvement pattern, given a trained model. 

+

4It can also compare this prediction to the observed prevalence in the data. As for the 

+

5risk prediction, this uses caching and computes the priors first. 

+

6""" 

+

7 

+

8from collections.abc import Callable 

+

9from typing import Literal 

+

10 

+

11import lydata # noqa: F401 

+

12import numpy as np 

+

13import pandas as pd 

+

14from loguru import logger 

+

15from lydata import C, Q 

+

16from lydata.accessor import NoneQ, QueryPortion 

+

17from lymph import models 

+

18from pydantic import Field 

+

19from rich import progress 

+

20 

+

21from lyscripts.cli import assemble_main 

+

22from lyscripts.compute.priors import compute_priors 

+

23from lyscripts.compute.utils import ( 

+

24 BaseComputeCLI, 

+

25 HDF5FileStorage, 

+

26 get_cached, 

+

27) 

+

28from lyscripts.configs import ( 

+

29 DataConfig, 

+

30 DiagnosisConfig, 

+

31 DistributionConfig, 

+

32 GraphConfig, 

+

33 ModalityConfig, 

+

34 ModelConfig, 

+

35 ScenarioConfig, 

+

36 add_distributions, 

+

37 add_modalities, 

+

38 construct_model, 

+

39) 

+

40from lyscripts.utils import console 

+

41 

+

42 

+

43def compute_prevalences( 

+

44 model_config: ModelConfig, 

+

45 graph_config: GraphConfig, 

+

46 dist_configs: dict[str, DistributionConfig], 

+

47 modality_configs: dict[str, ModalityConfig], 

+

48 priors: np.ndarray, 

+

49 diagnosis: dict[Literal["ipsi", "contra"], dict], 

+

50 midext: bool | None = None, 

+

51 progress_desc: str = "Computing prevalences from priors", 

+

52) -> np.ndarray: 

+

53 """Compute the prevalence of a diagnosis given the priors and the model.""" 

+

54 model = construct_model(model_config, graph_config) 

+

55 model = add_distributions(model, dist_configs) 

+

56 

+

57 if len(modality_configs) != 1: 

+

58 msg = "Only one modality is supported for prevalence prediction." 

+

59 logger.error(msg) 

+

60 raise ValueError(msg) 

+

61 

+

62 model = add_modalities(model, modality_configs) 

+

63 prevalences = [] 

+

64 kwargs = {"midext": midext} if isinstance(model, models.Midline) else {} 

+

65 

+

66 for prior in progress.track( 

+

67 sequence=priors, 

+

68 description=progress_desc, 

+

69 total=len(priors), 

+

70 console=console, 

+

71 ): 

+

72 obs_dist = model.obs_dist(given_state_dist=prior) 

+

73 involvement = { 

+

74 side: diagnosis.get(side).get(next(iter(modality_configs))) 

+

75 for side in ["ipsi", "contra"] 

+

76 } 

+

77 

+

78 if isinstance(model, models.Unilateral | models.HPVUnilateral): 

+

79 involvement = involvement.get("ipsi") 

+

80 

+

81 prevalence = model.marginalize( 

+

82 given_state_dist=obs_dist, 

+

83 involvement=involvement, 

+

84 **kwargs, 

+

85 ) 

+

86 

+

87 if isinstance(model, models.Midline): 

+

88 # In this case, we need to renormalize the prevalence by the marginalized 

+

89 # probability of all states with midline extension. We must do this, because 

+

90 # we compute the analogous quantity for the data. In principle, we could 

+

91 # also compute the prevalence of the diagnosis *and* midline extension, but 

+

92 # we have decided to compute the diagnosis *given* midline extension. 

+

93 # https://github.com/lycosystem/lyscripts/blob/ea49ec/lyscripts/compute/prevalences.py#L217-L225 

+

94 midext_prob = model.marginalize( 

+

95 involvement=None, 

+

96 given_state_dist=obs_dist, 

+

97 **kwargs, 

+

98 ) 

+

99 prevalence /= midext_prob 

+

100 

+

101 prevalences.append(prevalence) 

+

102 

+

103 return np.stack(prevalences) 

+

104 

+

105 

+

106def generate_query_from_diagnosis(diagnosis: DiagnosisConfig) -> Q: 

+

107 """Transform a diagnosis into a query for the data.""" 

+

108 result = NoneQ() 

+

109 for side in ["ipsi", "contra"]: 

+

110 for modality, pattern in getattr(diagnosis, side, {}).items(): 

+

111 for lnl, value in pattern.items(): 

+

112 column = (modality, side, lnl) 

+

113 result &= C(column) == value 

+

114 return result 

+

115 

+

116 

+

117def observe_prevalence( 

+

118 data: pd.DataFrame, 

+

119 scenario_config: ScenarioConfig, 

+

120 mapping: dict[int, str] | Callable[[int], str] | None = None, 

+

121) -> QueryPortion: 

+

122 """Extract prevalence defined in a ``scenario`` from the ``data``. 

+

123 

+

124 ``mapping`` defines how the T-stages in the data are supposed to be mapped to the 

+

125 T-stages defined in the ``scenario``. 

+

126 

+

127 It returns the number of patients that match the given scenario and the total 

+

128 number of patients that are considered. E.g., in the example below we 79 patients 

+

129 are of late T-stage and have a tumor extending over the midline. Of those, 30 were 

+

130 diagnosed with contralateral involvement in LNL II based on a CT scan. 

+

131 

+

132 >>> data = next(lydata.load_datasets(year=2021, institution="usz")) 

+

133 >>> scenario_config = ScenarioConfig( 

+

134 ... t_stages=["late"], 

+

135 ... midext=True, 

+

136 ... diagnosis=DiagnosisConfig(contra={"CT": {"II": True}}), 

+

137 ... ) 

+

138 >>> observe_prevalence(data, scenario_config) 

+

139 QueryPortion(match=np.int64(7), total=np.int64(79)) 

+

140 """ 

+

141 mapping = mapping or DataConfig.model_fields["mapping"].default_factory() 

+

142 data["tumor", "1", "t_stage"] = data.ly.t_stage.map(mapping) 

+

143 

+

144 has_t_stage = C("t_stage").isin(scenario_config.t_stages) 

+

145 if scenario_config.midext is None: 

+

146 has_midext = NoneQ() 

+

147 else: 

+

148 has_midext = C("midext") == scenario_config.midext 

+

149 

+

150 # Note that below we compute the prevalence of the diagnosis *given* midline 

+

151 # extension. This means, that when computing the prevalence of the diagnosis in 

+

152 # the model, we need to renormalize by diving by the probability of midline 

+

153 # extension. For an older - but pretty surely correct - implementation see 

+

154 # https://github.com/lycosystem/lyscripts/blob/ea49ec/lyscripts/compute/prevalences.py#L217-L225 

+

155 return data.ly.portion( 

+

156 query=generate_query_from_diagnosis(scenario_config.diagnosis), 

+

157 given=has_t_stage & has_midext, 

+

158 ) 

+

159 

+

160 

+

161class PrevalencesCLI(BaseComputeCLI): 

+

162 """Predict the prevalence of an involvement pattern from model samples.""" 

+

163 

+

164 modalities: dict[str, ModalityConfig] = Field( 

+

165 default={}, 

+

166 description=( 

+

167 "Maps names of diagnostic modalities to their specificity/sensitivity." 

+

168 ), 

+

169 ) 

+

170 prevalences: HDF5FileStorage = Field( 

+

171 description="Storage for the computed prevalences.", 

+

172 ) 

+

173 data: DataConfig 

+

174 

+

175 def cli_cmd(self) -> None: 

+

176 """Start the ``prevalences`` subcommand.""" 

+

177 logger.debug(self.model_dump_json(indent=2)) 

+

178 global_attrs = self.model_dump( 

+

179 include={"model", "graph", "distributions", "modalities"}, 

+

180 ) 

+

181 self.prevalences.set_attrs(attrs=global_attrs, dataset="/") 

+

182 

+

183 samples = self.sampling.load() 

+

184 cached_compute_priors = get_cached(compute_priors, self.cache_dir) 

+

185 cached_compute_prevalences = get_cached(compute_prevalences, self.cache_dir) 

+

186 num_scens = len(self.scenarios) 

+

187 

+

188 for i, scenario in enumerate(self.scenarios): 

+

189 _fields = {"t_stages", "t_stages_dist", "mode"} 

+

190 prior_kwargs = scenario.model_dump(include=_fields) 

+

191 

+

192 _priors = cached_compute_priors( 

+

193 model_config=self.model, 

+

194 graph_config=self.graph, 

+

195 dist_configs=self.distributions, 

+

196 samples=samples, 

+

197 progress_desc=f"Computing priors for scenario {i + 1}/{num_scens}", 

+

198 **prior_kwargs, 

+

199 ) 

+

200 

+

201 _fields = {"diagnosis", "midext"} 

+

202 prevalence_kwargs = scenario.model_dump(include=_fields) 

+

203 

+

204 prevalences = cached_compute_prevalences( 

+

205 model_config=self.model, 

+

206 graph_config=self.graph, 

+

207 dist_configs=self.distributions, 

+

208 modality_configs=self.modalities, 

+

209 priors=_priors, 

+

210 progress_desc=f"Computing prevalences for scenario {i + 1}/{num_scens}", 

+

211 **prevalence_kwargs, 

+

212 ) 

+

213 

+

214 portion = observe_prevalence( 

+

215 data=self.data.load(), 

+

216 scenario_config=scenario, 

+

217 mapping=self.data.mapping, 

+

218 ) 

+

219 self.prevalences.save(values=prevalences, dataset=f"{i:03d}") 

+

220 self.prevalences.set_attrs(attrs=prior_kwargs, dataset=f"{i:03d}") 

+

221 self.prevalences.set_attrs(attrs=prevalence_kwargs, dataset=f"{i:03d}") 

+

222 self.prevalences.set_attrs( 

+

223 attrs={ 

+

224 "num_match": portion.match, 

+

225 "num_total": portion.total, 

+

226 }, 

+

227 dataset=f"{i:03d}", 

+

228 ) 

+

229 

+

230 

+

231if __name__ == "__main__": 

+

232 main = assemble_main(settings_cls=PrevalencesCLI, prog_name="compute prevalences") 

+

233 main() 

+
+ + + diff --git a/htmlcov/z_055061514423972c_priors_py.html b/htmlcov/z_055061514423972c_priors_py.html new file mode 100644 index 0000000..0ed42d7 --- /dev/null +++ b/htmlcov/z_055061514423972c_priors_py.html @@ -0,0 +1,208 @@ + + + + + Coverage for src/lyscripts/compute/priors.py: 94% + + + + + +
+
+

+ Coverage for src/lyscripts/compute/priors.py: + 94% +

+ +

+ 35 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Given samples drawn during an MCMC round, compute the (prior) state distributions. 

+

2 

+

3This is done for each sample and for a list of specified scenarios. The computation is 

+

4cached at a location specified by the ``--cache_dir`` argument using ``joblib``. 

+

5""" 

+

6 

+

7from typing import Literal 

+

8 

+

9import numpy as np 

+

10from loguru import logger 

+

11from pydantic import Field 

+

12from rich import progress 

+

13 

+

14from lyscripts.cli import assemble_main 

+

15from lyscripts.compute.utils import BaseComputeCLI, HDF5FileStorage, get_cached 

+

16from lyscripts.configs import ( 

+

17 DistributionConfig, 

+

18 GraphConfig, 

+

19 ModelConfig, 

+

20 add_distributions, 

+

21 construct_model, 

+

22) 

+

23from lyscripts.utils import console 

+

24 

+

25 

+

26def compute_priors( 

+

27 model_config: ModelConfig, 

+

28 graph_config: GraphConfig, 

+

29 dist_configs: dict[str, DistributionConfig], 

+

30 samples: np.ndarray, 

+

31 t_stages: list[int | str], 

+

32 t_stages_dist: list[float], 

+

33 mode: Literal["HMM", "BN"] = "HMM", 

+

34 progress_desc: str = "Computing priors from samples", 

+

35) -> np.ndarray: 

+

36 """Compute prior state distributions from the ``samples`` for the ``model``. 

+

37 

+

38 This will call the ``model`` method :py:meth:`~lymph.types.Model.state_dist` 

+

39 for each of the ``samples``. The prior state distributions are computed for 

+

40 each of the ``t_stages`` and marginalized over using the ``t_stages_dist``. 

+

41 """ 

+

42 model = construct_model(model_config, graph_config) 

+

43 model = add_distributions(model, dist_configs) 

+

44 priors = [] 

+

45 

+

46 for sample in progress.track( 

+

47 sequence=samples, 

+

48 description=progress_desc, 

+

49 total=len(samples), 

+

50 console=console, 

+

51 ): 

+

52 model.set_params(*sample) 

+

53 priors.append( 

+

54 sum( 

+

55 model.state_dist(t_stage=t, mode=mode) * p 

+

56 for t, p in zip(t_stages, t_stages_dist, strict=False) 

+

57 ), 

+

58 ) 

+

59 

+

60 return np.stack(priors) 

+

61 

+

62 

+

63class PriorsCLI(BaseComputeCLI): 

+

64 """Compute the prior state distributions from MCMC samples.""" 

+

65 

+

66 priors: HDF5FileStorage = Field(description="Storage for the computed priors.") 

+

67 

+

68 def cli_cmd(self) -> None: 

+

69 """Start the ``priors`` subcommand. 

+

70 

+

71 Given a ``graph``, ``model``, ``distributions`` over diagnosis times, and 

+

72 MCMC samples loaded from the ``sampling`` argument, this command computes the 

+

73 prior state distributions for each of the specified ``scenarios``. 

+

74 

+

75 Precomputing these state distributions is useful, because they largely only 

+

76 depend on T-stage and not on the diagnosis or involvement of interest. Hence, 

+

77 computing the :py:mod:`~lyscripts.compute.posteriors` and 

+

78 :py:mod:`~lyscripts.compute.risks` can be sped up. 

+

79 

+

80 Note that this command will use `joblib`_ to cache its computations. 

+

81 

+

82 .. _joblib: https://joblib.readthedocs.io/ 

+

83 """ 

+

84 logger.debug(self.model_dump_json(indent=2)) 

+

85 global_attrs = self.model_dump(include={"model", "graph", "distributions"}) 

+

86 self.priors.set_attrs(attrs=global_attrs, dataset="/") 

+

87 

+

88 samples = self.sampling.load() 

+

89 cached_compute_priors = get_cached(compute_priors, self.cache_dir) 

+

90 num_scenarios = len(self.scenarios) 

+

91 

+

92 for i, scenario in enumerate(self.scenarios): 

+

93 _fields = {"t_stages", "t_stages_dist", "mode"} 

+

94 prior_kwargs = scenario.model_dump(include=_fields) 

+

95 

+

96 priors = cached_compute_priors( 

+

97 model_config=self.model, 

+

98 graph_config=self.graph, 

+

99 dist_configs=self.distributions, 

+

100 samples=samples, 

+

101 progress_desc=f"Computing priors for scenario {i + 1}/{num_scenarios}", 

+

102 **prior_kwargs, 

+

103 ) 

+

104 

+

105 self.priors.save(values=priors, dataset=f"{i:03d}") 

+

106 self.priors.set_attrs(attrs=prior_kwargs, dataset=f"{i:03d}") 

+

107 

+

108 

+

109if __name__ == "__main__": 

+

110 main = assemble_main(settings_cls=PriorsCLI, prog_name="compute priors") 

+

111 main() 

+
+ + + diff --git a/htmlcov/z_055061514423972c_risks_py.html b/htmlcov/z_055061514423972c_risks_py.html new file mode 100644 index 0000000..48b0011 --- /dev/null +++ b/htmlcov/z_055061514423972c_risks_py.html @@ -0,0 +1,237 @@ + + + + + Coverage for src/lyscripts/compute/risks.py: 35% + + + + + +
+
+

+ Coverage for src/lyscripts/compute/risks.py: + 35% +

+ +

+ 51 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Predict risks of involvements for scenarios using drawn MCMC samples. 

+

2 

+

3As the priors and posteriors, this computation, too, uses caching and may skip the 

+

4computation of these two initial steps if the cache directory is the same as during 

+

5their computation. 

+

6""" 

+

7 

+

8from typing import Literal 

+

9 

+

10import numpy as np 

+

11from loguru import logger 

+

12from lymph import models 

+

13from pydantic import Field 

+

14from rich import progress 

+

15 

+

16from lyscripts.cli import assemble_main 

+

17from lyscripts.compute.posteriors import compute_posteriors 

+

18from lyscripts.compute.priors import compute_priors 

+

19from lyscripts.compute.utils import BaseComputeCLI, HDF5FileStorage, get_cached 

+

20from lyscripts.configs import ( 

+

21 DistributionConfig, 

+

22 GraphConfig, 

+

23 ModalityConfig, 

+

24 ModelConfig, 

+

25 add_distributions, 

+

26 add_modalities, 

+

27 construct_model, 

+

28) 

+

29from lyscripts.utils import console 

+

30 

+

31 

+

32def compute_risks( 

+

33 model_config: ModelConfig, 

+

34 graph_config: GraphConfig, 

+

35 dist_configs: dict[str, DistributionConfig], 

+

36 modality_configs: dict[str, ModalityConfig], 

+

37 posteriors: np.ndarray, 

+

38 involvement: dict[Literal["ipsi", "contra"], dict], 

+

39 progress_desc: str = "Computing risks from posteriors", 

+

40) -> np.ndarray: 

+

41 """Compute the risk of ``involvement`` from each of the ``posteriors``. 

+

42 

+

43 Essentially, this only calls the model's :py:meth:`lymph.models.Model.marginalize` 

+

44 method, as nothing more is necessary than to marginalize the full posterior state 

+

45 distribution over the states that correspond to the involvement of interest. 

+

46 """ 

+

47 model = construct_model(model_config, graph_config) 

+

48 model = add_distributions(model, dist_configs) 

+

49 model = add_modalities(model, modality_configs) 

+

50 risks = [] 

+

51 

+

52 if isinstance(model, models.Unilateral | models.HPVUnilateral): 

+

53 involvement = involvement.get("ipsi") 

+

54 

+

55 for posterior in progress.track( 

+

56 sequence=posteriors, 

+

57 description=progress_desc, 

+

58 total=len(posteriors), 

+

59 console=console, 

+

60 ): 

+

61 risks.append( 

+

62 model.marginalize(involvement=involvement, given_state_dist=posterior), 

+

63 ) 

+

64 

+

65 return np.stack(risks) 

+

66 

+

67 

+

68class RisksCLI(BaseComputeCLI): 

+

69 """Predict the risk of involvement scenarios from model samples given diagnoses.""" 

+

70 

+

71 modalities: dict[str, ModalityConfig] = Field( 

+

72 default={}, 

+

73 description=( 

+

74 "Maps names of diagnostic modalities to their specificity/sensitivity." 

+

75 ), 

+

76 ) 

+

77 risks: HDF5FileStorage = Field(description="Storage for the computed risks.") 

+

78 

+

79 def cli_cmd(self) -> None: 

+

80 """Start the ``risks`` subcommand.""" 

+

81 logger.debug(self.model_dump_json(indent=2)) 

+

82 global_attrs = self.model_dump( 

+

83 include={"model", "graph", "distributions", "modalities"}, 

+

84 ) 

+

85 self.risks.set_attrs(attrs=global_attrs, dataset="/") 

+

86 

+

87 samples = self.sampling.load() 

+

88 cached_compute_priors = get_cached(compute_priors, self.cache_dir) 

+

89 cached_compute_posteriors = get_cached(compute_posteriors, self.cache_dir) 

+

90 cached_compute_risks = get_cached(compute_risks, self.cache_dir) 

+

91 num_scens = len(self.scenarios) 

+

92 

+

93 for i, scenario in enumerate(self.scenarios): 

+

94 _fields = {"t_stages", "t_stages_dist", "mode"} 

+

95 prior_kwargs = scenario.model_dump(include=_fields) 

+

96 

+

97 _priors = cached_compute_priors( 

+

98 model_config=self.model, 

+

99 graph_config=self.graph, 

+

100 dist_configs=self.distributions, 

+

101 samples=samples, 

+

102 progress_desc=f"Computing priors for scenario {i + 1}/{num_scens}", 

+

103 **prior_kwargs, 

+

104 ) 

+

105 

+

106 _fields = {"diagnosis", "midext", "mode"} 

+

107 posterior_kwargs = scenario.model_dump(include=_fields) 

+

108 

+

109 _posteriors = cached_compute_posteriors( 

+

110 model_config=self.model, 

+

111 graph_config=self.graph, 

+

112 dist_configs=self.distributions, 

+

113 modality_configs=self.modalities, 

+

114 priors=_priors, 

+

115 progress_desc=f"Computing posteriors for scenario {i + 1}/{num_scens}", 

+

116 **posterior_kwargs, 

+

117 ) 

+

118 

+

119 _fields = {"involvement"} 

+

120 risk_kwargs = scenario.model_dump(include=_fields) 

+

121 

+

122 risks = cached_compute_risks( 

+

123 model_config=self.model, 

+

124 graph_config=self.graph, 

+

125 dist_configs=self.distributions, 

+

126 modality_configs=self.modalities, 

+

127 posteriors=_posteriors, 

+

128 progress_desc=f"Computing risks for scenario {i + 1}/{num_scens}", 

+

129 **risk_kwargs, 

+

130 ) 

+

131 

+

132 self.risks.save(values=risks, dataset=f"{i:03d}") 

+

133 self.risks.set_attrs(attrs=prior_kwargs, dataset=f"{i:03d}") 

+

134 self.risks.set_attrs(attrs=posterior_kwargs, dataset=f"{i:03d}") 

+

135 self.risks.set_attrs(attrs=risk_kwargs, dataset=f"{i:03d}") 

+

136 

+

137 

+

138if __name__ == "__main__": 

+

139 main = assemble_main(settings_cls=RisksCLI, prog_name="compute risks") 

+

140 main() 

+
+ + + diff --git a/htmlcov/z_055061514423972c_utils_py.html b/htmlcov/z_055061514423972c_utils_py.html new file mode 100644 index 0000000..32e8efb --- /dev/null +++ b/htmlcov/z_055061514423972c_utils_py.html @@ -0,0 +1,373 @@ + + + + + Coverage for src/lyscripts/compute/utils.py: 95% + + + + + +
+
+

+ Coverage for src/lyscripts/compute/utils.py: + 95% +

+ +

+ 120 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Utilities for precomputing the priors and posteriors.""" 

+

2 

+

3import ast 

+

4import functools 

+

5from pathlib import Path 

+

6from typing import Annotated, Any 

+

7 

+

8import h5py 

+

9import numpy as np 

+

10from joblib import Memory 

+

11from loguru import logger 

+

12from pydantic import AfterValidator, BaseModel, Field 

+

13 

+

14from lyscripts.configs import ( 

+

15 BaseCLI, 

+

16 DistributionConfig, 

+

17 GraphConfig, 

+

18 ModelConfig, 

+

19 SamplingConfig, 

+

20 ScenarioConfig, 

+

21) 

+

22 

+

23 

+

24class BaseComputeCLI(BaseCLI): 

+

25 """Common command line settings for the submodule ``compute``.""" 

+

26 

+

27 graph: GraphConfig 

+

28 model: ModelConfig = ModelConfig() 

+

29 distributions: dict[str, DistributionConfig] = Field( 

+

30 default={}, 

+

31 description=( 

+

32 "Mapping of model T-categories to predefined distributions over " 

+

33 "diagnose times." 

+

34 ), 

+

35 ) 

+

36 cache_dir: Path = Field( 

+

37 default=Path.cwd() / ".cache", 

+

38 description="Cache directory for storing function calls.", 

+

39 ) 

+

40 scenarios: list[ScenarioConfig] = Field( 

+

41 default=[], 

+

42 description="List of scenarios to compute risks for.", 

+

43 ) 

+

44 sampling: SamplingConfig 

+

45 

+

46 

+

47def is_hdf5_compatible(value: Any) -> bool: 

+

48 """Check if the given ``value`` can be stored in an HDF5 file.""" 

+

49 return isinstance( 

+

50 value, 

+

51 bool | str | bytes | int | float | np.ndarray | list | tuple, 

+

52 ) 

+

53 

+

54 

+

55def to_hdf5_attrs(mapping: dict[str, Any]) -> dict[str, str]: 

+

56 """Convert ``attrs`` to a dictionary of HDF5 compatible attributes or strings.""" 

+

57 res = {} 

+

58 for key, val in mapping.items(): 

+

59 if is_hdf5_compatible(val): 

+

60 res[key] = val 

+

61 else: 

+

62 res[key] = str(val) 

+

63 return res 

+

64 

+

65 

+

66def from_hdf5_attrs(mapping: h5py.AttributeManager) -> dict[str, Any]: 

+

67 """Convert the HDF5 attributes to a dictionary of Python objects.""" 

+

68 attrs = {} 

+

69 for key, value in mapping.items(): 

+

70 try: 

+

71 attrs[key] = ast.literal_eval(value) 

+

72 except ValueError: 

+

73 attrs[key] = value 

+

74 return attrs 

+

75 

+

76 

+

77def extract_modalities(diagnosis: dict[str, Any]) -> set[str]: 

+

78 """Get the set of modalities used in the ``diagnosis``. 

+

79 

+

80 This is not used in the main apps anymore, but since it may be useful, I keep it. 

+

81 

+

82 >>> diagnosis = { 

+

83 ... "ipsi": { 

+

84 ... "MRI": {"II": True, "III": False}, 

+

85 ... "PET": {"II": False, "III": True}, 

+

86 ... }, 

+

87 ... "contra": {"MRI": {"II": False, "III": None}}, 

+

88 ... } 

+

89 >>> sorted(extract_modalities(diagnosis)) 

+

90 ['MRI', 'PET'] 

+

91 """ 

+

92 modality_set = set() 

+

93 

+

94 if "ipsi" not in diagnosis and "contra" not in diagnosis: 

+

95 return modality_set | set(diagnosis.keys()) 

+

96 

+

97 for side in ["ipsi", "contra"]: 

+

98 if side in diagnosis: 

+

99 modality_set |= set(diagnosis[side].keys()) 

+

100 

+

101 return modality_set 

+

102 

+

103 

+

104def ensure_parent_dir(path: Path) -> Path: 

+

105 """Create the parent directory of the given ``path``.""" 

+

106 path.parent.mkdir(parents=True, exist_ok=True) 

+

107 logger.debug(f"Ensured parent directory of {path}") 

+

108 return path 

+

109 

+

110 

+

111HasParentPath = Annotated[Path, AfterValidator(ensure_parent_dir)] 

+

112"""Type hint for path whose parent dir is created if it doesn't exist.""" 

+

113 

+

114 

+

115class HDF5FileStorage(BaseModel): 

+

116 """HDF5 file storage for in- and outputs of computations.""" 

+

117 

+

118 file: HasParentPath = Field( 

+

119 description="Path to the HDF5 file. Parent directories are created if needed.", 

+

120 ) 

+

121 dataset: str | None = Field( 

+

122 default=None, 

+

123 description=( 

+

124 "Name of the dataset in the HDF5 file. Save/load methods can override this." 

+

125 ), 

+

126 ) 

+

127 

+

128 def _get_dataset(self) -> str: 

+

129 """Get attribute ``dataset`` or the first dataset in the file. 

+

130 

+

131 >>> from tempfile import TemporaryDirectory 

+

132 >>> tmp_path = Path(TemporaryDirectory().name) / "test.hdf5" 

+

133 >>> storage = HDF5FileStorage(file=tmp_path) 

+

134 >>> rand_data = np.random.rand(100, 100) 

+

135 >>> storage.save(values=rand_data, dataset="test") 

+

136 >>> np.all(storage.load(dataset="test") == rand_data) 

+

137 np.True_ 

+

138 >>> np.all(storage.load() == rand_data) # loads first dataset 

+

139 np.True_ 

+

140 >>> some_attrs = {"key": "value"} 

+

141 >>> storage.set_attrs(attrs=some_attrs, dataset="test") 

+

142 >>> storage.get_attrs(dataset="test") 

+

143 {'key': 'value'} 

+

144 """ 

+

145 if self.dataset is not None: 

+

146 return self.dataset 

+

147 

+

148 with h5py.File(self.file, "r") as file: 

+

149 return next(iter(file.keys())) 

+

150 

+

151 def load(self, dataset: str | None = None) -> np.ndarray: 

+

152 """Load the dataset with the name ``dataset``.""" 

+

153 dataset = dataset or self._get_dataset() 

+

154 

+

155 with h5py.File(self.file, "r") as file: 

+

156 array = file[dataset][()] 

+

157 

+

158 logger.debug(f"Loaded dataset {dataset} from {self.file}") 

+

159 return array 

+

160 

+

161 def get_attrs(self, dataset: str | None = None) -> dict[str, Any]: 

+

162 """Get the attributes of the dataset ``dataset``.""" 

+

163 dataset = dataset or self._get_dataset() 

+

164 

+

165 with h5py.File(self.file, "r") as file: 

+

166 attrs = from_hdf5_attrs(file[dataset].attrs) 

+

167 

+

168 logger.debug(f"Loaded attrs for dataset '{dataset}' from {self.file}") 

+

169 return attrs 

+

170 

+

171 def save(self, values: np.ndarray, dataset: str | None = None) -> None: 

+

172 """Set the ``values`` for the ``dataset`` dataset.""" 

+

173 dataset = dataset or self._get_dataset() 

+

174 

+

175 with h5py.File(self.file, "a") as file: 

+

176 if dataset in file: 

+

177 del file[dataset] 

+

178 file[dataset] = values 

+

179 

+

180 logger.debug(f"Stored dataset {dataset} in {self.file}") 

+

181 

+

182 def set_attrs(self, attrs: dict[str, Any], dataset: str | None = None) -> None: 

+

183 """Update the ``attrs`` for the ``dataset`` dataset.""" 

+

184 dataset = dataset or self._get_dataset() 

+

185 

+

186 with h5py.File(self.file, "a") as file: 

+

187 if dataset not in file: 

+

188 raise ValueError(f"Dataset '{dataset}' not found in {self.file}") 

+

189 file[dataset].attrs.update(to_hdf5_attrs(attrs)) 

+

190 

+

191 logger.debug(f"Stored attrs {attrs} for dataset '{dataset}' in {self.file}") 

+

192 

+

193 

+

194def reduce_pattern(pattern: dict[str, dict[str, bool]]) -> dict[str, dict[str, bool]]: 

+

195 """Reduce a ``pattern`` by removing all entries that are ``None``. 

+

196 

+

197 This way, it should be completely recoverable by the ``complete_pattern`` function 

+

198 but be shorter to store. 

+

199 

+

200 Unused but maybe useful for some cases. Keeping it in here for now. 

+

201 

+

202 >>> full = { 

+

203 ... "ipsi": {"I": None, "II": True, "III": None}, 

+

204 ... "contra": {"I": None, "II": None, "III": None}, 

+

205 ... } 

+

206 >>> reduce_pattern(full) 

+

207 {'ipsi': {'II': True}} 

+

208 

+

209 """ 

+

210 tmp_pattern = pattern.copy() 

+

211 reduced_pattern = {} 

+

212 for side in ["ipsi", "contra"]: 

+

213 if not all(v is None for v in tmp_pattern[side].values()): 

+

214 reduced_pattern[side] = {} 

+

215 for lnl, val in tmp_pattern[side].items(): 

+

216 if val is not None: 

+

217 reduced_pattern[side][lnl] = val 

+

218 

+

219 return reduced_pattern 

+

220 

+

221 

+

222def complete_pattern( 

+

223 pattern: dict[str, dict[str, bool]] | None, 

+

224 lnls: list[str], 

+

225) -> dict[str, dict[str, bool]]: 

+

226 """Make sure the provided involvement ``pattern`` is correct. 

+

227 

+

228 For each side of the neck, and for each of the ``lnls`` this should in the end 

+

229 contain ``True``, ``False`` or ``None``. 

+

230 

+

231 Unused but maybe useful for some cases. Keeping it in here for now. 

+

232 

+

233 >>> pattern = {"ipsi": {"II": True}} 

+

234 >>> lnls = ["II", "III"] 

+

235 >>> complete_pattern(pattern, lnls) 

+

236 {'ipsi': {'II': True, 'III': None}, 'contra': {'II': None, 'III': None}} 

+

237 

+

238 """ 

+

239 if pattern is None: 

+

240 pattern = {} 

+

241 

+

242 for side in ["ipsi", "contra"]: 

+

243 if side not in pattern: 

+

244 pattern[side] = {} 

+

245 

+

246 for lnl in lnls: 

+

247 if lnl not in pattern[side]: 

+

248 pattern[side][lnl] = None 

+

249 elif pattern[side][lnl] is None: 

+

250 continue 

+

251 else: 

+

252 pattern[side][lnl] = bool(pattern[side][lnl]) 

+

253 

+

254 return pattern 

+

255 

+

256 

+

257def get_cached(func: callable, cache_dir: Path) -> callable: 

+

258 """Return cached ``func`` with a cache at ``cache_dir``.""" 

+

259 memory = Memory(location=cache_dir, verbose=0) 

+

260 cached_func = memory.cache(func, ignore=["progress_desc"]) 

+

261 logger.info(f"Initialized cache for {func.__name__} at {cache_dir}") 

+

262 

+

263 @functools.wraps(func) 

+

264 def log_cache_info_wrapper(*args, **kwargs): 

+

265 logger.debug(f"Calling {func.__name__}({args}, {kwargs})") 

+

266 if cached_func.check_call_in_cache(*args, **kwargs): 

+

267 logger.info(f"Cache hit for {func.__name__}, returning stored result") 

+

268 else: 

+

269 logger.info(f"Cache miss for {func.__name__}, computing result") 

+

270 

+

271 result = cached_func(*args, **kwargs) 

+

272 logger.debug(f"Computed {result = }") 

+

273 return result 

+

274 

+

275 log_cache_info_wrapper._cached_func = cached_func 

+

276 return log_cache_info_wrapper 

+
+ + + diff --git a/htmlcov/z_5bf5c588c698c6cc___init___py.html b/htmlcov/z_5bf5c588c698c6cc___init___py.html new file mode 100644 index 0000000..fe6eb02 --- /dev/null +++ b/htmlcov/z_5bf5c588c698c6cc___init___py.html @@ -0,0 +1,172 @@ + + + + + Coverage for src/lyscripts/__init__.py: 79% + + + + + +
+
+

+ Coverage for src/lyscripts/__init__.py: + 79% +

+ +

+ 34 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Initial entry point for the lyscripts package and CLIs. 

+

2 

+

3This top-level module configures and provides the top-level CLI through which all 

+

4subcommands can be accessed. 

+

5""" 

+

6 

+

7import sys 

+

8from typing import Literal 

+

9 

+

10import pandas as pd 

+

11from loguru import logger 

+

12from pydantic import Field 

+

13from pydantic_settings import ( 

+

14 BaseSettings, 

+

15 CliApp, 

+

16 CliImplicitFlag, 

+

17 CliSubCommand, 

+

18) 

+

19 

+

20from lyscripts import compute, data, sample, schedule # noqa: F401 

+

21from lyscripts._version import version 

+

22from lyscripts.cli import assemble_main, configure_logging 

+

23from lyscripts.utils import console 

+

24 

+

25__version__ = version 

+

26__description__ = "Package to interact with lymphatic progression data and models." 

+

27__author__ = "Roman Ludwig" 

+

28__email__ = "roman.ludwig@usz.ch" 

+

29__uri__ = "https://github.com/lycosystem/lyscripts" 

+

30 

+

31# activate copy on write in pandas. 

+

32# See https://pandas.pydata.org/docs/user_guide/copy_on_write.html 

+

33pd.options.mode.copy_on_write = True 

+

34 

+

35logger.disable("lyscripts") 

+

36 

+

37 

+

38class LyscriptsCLI(BaseSettings): 

+

39 """A CLI to interact with lymphatic progression data and models.""" 

+

40 

+

41 version: CliImplicitFlag[bool] = Field( 

+

42 default=False, 

+

43 description="Display the version of lyscripts and exit.", 

+

44 ) 

+

45 log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = Field( 

+

46 default="INFO", 

+

47 description="Set the log level of the lyscripts CLI.", 

+

48 ) 

+

49 

+

50 data: CliSubCommand[data.DataCLI] 

+

51 sample: CliSubCommand[sample.SampleCLI] 

+

52 compute: CliSubCommand[compute.ComputeCLI] 

+

53 schedule: CliSubCommand[schedule.ScheduleCLI] 

+

54 

+

55 def __init__(self, **kwargs): 

+

56 """Add logging configuration to the lyscripts CLI.""" 

+

57 configure_logging(argv=sys.argv, console=console) 

+

58 super().__init__(**kwargs) 

+

59 

+

60 def cli_cmd(self) -> None: 

+

61 """Start the main lyscripts CLI. 

+

62 

+

63 If the ``version`` flag is set, the version of lyscripts is displayed and the 

+

64 program exits. Otherwise, the lyscripts CLI runs one of the subcommands. 

+

65 """ 

+

66 logger.debug("Starting lyscripts CLI.") 

+

67 

+

68 if self.version: 

+

69 logger.info(f"lyscripts {__version__}") 

+

70 return 

+

71 

+

72 CliApp.run_subcommand(self) 

+

73 

+

74 

+

75main = assemble_main(settings_cls=LyscriptsCLI, prog_name="lyscripts") 

+
+ + + diff --git a/htmlcov/z_5bf5c588c698c6cc___main___py.html b/htmlcov/z_5bf5c588c698c6cc___main___py.html new file mode 100644 index 0000000..2ec7cf5 --- /dev/null +++ b/htmlcov/z_5bf5c588c698c6cc___main___py.html @@ -0,0 +1,103 @@ + + + + + Coverage for src/lyscripts/__main__.py: 0% + + + + + +
+
+

+ Coverage for src/lyscripts/__main__.py: + 0% +

+ +

+ 3 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Utility for common tasks w.r.t. inference & prediction using `lymph` package.""" 

+

2 

+

3from lyscripts import main 

+

4 

+

5if __name__ == "__main__": 

+

6 main() 

+
+ + + diff --git a/htmlcov/z_5bf5c588c698c6cc__version_py.html b/htmlcov/z_5bf5c588c698c6cc__version_py.html new file mode 100644 index 0000000..de0995a --- /dev/null +++ b/htmlcov/z_5bf5c588c698c6cc__version_py.html @@ -0,0 +1,118 @@ + + + + + Coverage for src/lyscripts/_version.py: 77% + + + + + +
+
+

+ Coverage for src/lyscripts/_version.py: + 77% +

+ +

+ 13 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1# file generated by setuptools-scm 

+

2# don't change, don't track in version control 

+

3 

+

4__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"] 

+

5 

+

6TYPE_CHECKING = False 

+

7if TYPE_CHECKING: 

+

8 from typing import Tuple 

+

9 from typing import Union 

+

10 

+

11 VERSION_TUPLE = Tuple[Union[int, str], ...] 

+

12else: 

+

13 VERSION_TUPLE = object 

+

14 

+

15version: str 

+

16__version__: str 

+

17__version_tuple__: VERSION_TUPLE 

+

18version_tuple: VERSION_TUPLE 

+

19 

+

20__version__ = version = '0.1.dev1' 

+

21__version_tuple__ = version_tuple = (0, 1, 'dev1') 

+
+ + + diff --git a/htmlcov/z_5bf5c588c698c6cc_cli_py.html b/htmlcov/z_5bf5c588c698c6cc_cli_py.html new file mode 100644 index 0000000..d9f8fd6 --- /dev/null +++ b/htmlcov/z_5bf5c588c698c6cc_cli_py.html @@ -0,0 +1,187 @@ + + + + + Coverage for src/lyscripts/cli.py: 54% + + + + + +
+
+

+ Coverage for src/lyscripts/cli.py: + 54% +

+ +

+ 26 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Utilities for configuring and running CLIs app. 

+

2 

+

3In this module, we define and configure a :py:class:`RichDefaultHelpFormatter` that 

+

4nicely displays the CLI's ``--help`` text. We also provide a function to 

+

5:py:func:`assemble a main function <assemble_main>` for the different CLI apps to save 

+

6some boilerplate code. Lastly, we have two functions related to the `loguru`_ setup. 

+

7 

+

8.. _loguru: https://loguru.readthedocs.io/en/stable 

+

9""" 

+

10 

+

11from collections.abc import Callable 

+

12from typing import Literal 

+

13 

+

14from loguru import logger 

+

15from pydantic_settings import BaseSettings, CliApp, CliSettingsSource 

+

16from rich.console import Console 

+

17from rich.logging import RichHandler 

+

18from rich_argparse import ArgumentDefaultsRichHelpFormatter 

+

19 

+

20 

+

21def assemble_main( 

+

22 settings_cls: type[BaseSettings], 

+

23 prog_name: str, 

+

24) -> Callable[[], None]: 

+

25 """Assemble a ``main()`` function for a CLI app. 

+

26 

+

27 It creates a :py:class:`~pydantic_settings.CliSettingsSource` object with the 

+

28 provided ``settings_cls`` and ``prog_name``. Then, it fills in some default 

+

29 settings for the CLI configuration and runs the CLI app. 

+

30 

+

31 Assembling a ``main()`` function for all subcommands like this saves some 

+

32 boilerplate code. 

+

33 """ 

+

34 

+

35 def main() -> None: 

+

36 """Start the main CLI app.""" 

+

37 cli_settings_source = CliSettingsSource( 

+

38 settings_cls=settings_cls, 

+

39 cli_prog_name=prog_name, 

+

40 cli_kebab_case=True, 

+

41 cli_use_class_docs_for_groups=True, 

+

42 formatter_class=ArgumentDefaultsRichHelpFormatter, 

+

43 ) 

+

44 CliApp.run(settings_cls, cli_settings_source=cli_settings_source) 

+

45 

+

46 return main 

+

47 

+

48 

+

49def somewhat_safely_get_loglevel( 

+

50 argv: list[str], 

+

51) -> Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]: 

+

52 """Set the log level of the lyscripts CLI. 

+

53 

+

54 This is a bit of a hack, since the :py:class:`~lyscripts.LyscriptsCLI` class is not 

+

55 yet initialized when we need to set the log level. In case the provided log-level is 

+

56 not valid, :py:class:`~lyscripts.LyscriptsCLI` will raise an exception at a later 

+

57 point. 

+

58 

+

59 Return ``"INFO"`` by default. 

+

60 """ 

+

61 args_str = " ".join(argv) 

+

62 if "--log-level" in args_str: 

+

63 for log_level in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]: 

+

64 if log_level in args_str: 

+

65 return log_level 

+

66 

+

67 return "INFO" 

+

68 

+

69 

+

70def configure_logging( 

+

71 argv: list[str], 

+

72 console: Console, 

+

73) -> None: 

+

74 """Configure the `loguru`_ logging system of the lyscripts CLI. 

+

75 

+

76 This function sets the log level and format of the lyscripts CLI. Notably, for 

+

77 a log-level of `DEBUG` the output will contain more information. 

+

78 

+

79 .. _loguru: https://loguru.readthedocs.io/en/stable 

+

80 """ 

+

81 logger.enable("lyscripts") 

+

82 logger.enable("lydata") 

+

83 log_level = somewhat_safely_get_loglevel(argv=argv) 

+

84 logger.remove() 

+

85 handler = RichHandler(console=console) 

+

86 logger.add( 

+

87 sink=handler, 

+

88 level=log_level, 

+

89 format="<lvl>{message}</>", 

+

90 ) 

+
+ + + diff --git a/htmlcov/z_5bf5c588c698c6cc_configs_py.html b/htmlcov/z_5bf5c588c698c6cc_configs_py.html new file mode 100644 index 0000000..44807f3 --- /dev/null +++ b/htmlcov/z_5bf5c588c698c6cc_configs_py.html @@ -0,0 +1,847 @@ + + + + + Coverage for src/lyscripts/configs.py: 89% + + + + + +
+
+

+ Coverage for src/lyscripts/configs.py: + 89% +

+ +

+ 255 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Using `pydantic`_, we define configurations for the package. 

+

2 

+

3Most importantly, these configurations are part of the CLIs that the package provides. 

+

4but they also help with programmatically validating and constructing various objects. 

+

5Maybe most importantly, the :py:class:`GraphConfig` and :py:class:`ModelConfig` may be 

+

6used to precisely and reproducibly define how the function :py:func:`construct_model` 

+

7should create lymphatic progression :py:mod:`~lymph.models`. 

+

8 

+

9.. _pydantic: https://docs.pydantic.dev/latest/ 

+

10""" 

+

11 

+

12from __future__ import annotations 

+

13 

+

14import importlib 

+

15import importlib.util 

+

16import os 

+

17import warnings 

+

18from collections.abc import Callable, Sequence 

+

19from copy import deepcopy 

+

20from pathlib import Path 

+

21from typing import Annotated, Any, Literal 

+

22 

+

23import numpy as np 

+

24import pandas as pd 

+

25import yaml 

+

26from loguru import logger 

+

27from lydata.loader import LyDataset 

+

28from lydata.utils import ModalityConfig 

+

29from lymph import graph, models 

+

30from lymph.modalities import Pathological 

+

31from lymph.types import Model, PatternType 

+

32from pydantic import ( 

+

33 AfterValidator, 

+

34 BaseModel, 

+

35 ConfigDict, 

+

36 Field, 

+

37 FilePath, 

+

38) 

+

39from pydantic_settings import ( 

+

40 BaseSettings, 

+

41 PydanticBaseSettingsSource, 

+

42 YamlConfigSettingsSource, 

+

43) 

+

44from pydantic_settings.sources import DEFAULT_PATH 

+

45 

+

46from lyscripts.utils import binom_pmf, flatten, load_model_samples, load_patient_data 

+

47 

+

48FuncNameType = Literal["binomial"] 

+

49 

+

50 

+

51DIST_MAP: dict[FuncNameType, Callable] = { 

+

52 "binomial": binom_pmf, 

+

53} 

+

54 

+

55 

+

56class CrossValidationConfig(BaseModel): 

+

57 """Configs for splitting a dataset into cross-validation folds.""" 

+

58 

+

59 seed: int = Field( 

+

60 default=42, 

+

61 description="Seed for the random number generator.", 

+

62 ) 

+

63 folds: int = Field( 

+

64 default=5, 

+

65 description="Number of folds to split the dataset into.", 

+

66 ) 

+

67 

+

68 

+

69class DataConfig(BaseModel): 

+

70 """Where to load lymphatic progression data from and how to feed it into a model.""" 

+

71 

+

72 source: FilePath | LyDataset = Field( 

+

73 description=( 

+

74 "Either a path to a CSV file or a config that specifies how and where " 

+

75 "to fetch the data from." 

+

76 ), 

+

77 ) 

+

78 side: Literal["ipsi", "contra"] | None = Field( 

+

79 default=None, 

+

80 description="Side of the neck to load data for. Only for Unilateral models.", 

+

81 ) 

+

82 mapping: dict[Literal[0, 1, 2, 3, 4] | str, int | str] = Field( 

+

83 default_factory=lambda: {i: "early" if i <= 2 else "late" for i in range(5)}, 

+

84 description="Optional mapping of numeric T-stages to model T-stages.", 

+

85 ) 

+

86 

+

87 def load(self, **get_dataframe_kwargs) -> pd.DataFrame: 

+

88 """Load data from path or the :py:class:`~lydata.loader.LyDataset`.""" 

+

89 if isinstance(self.source, LyDataset): 

+

90 return self.source.get_dataframe(**get_dataframe_kwargs) 

+

91 

+

92 return load_patient_data(self.source, **get_dataframe_kwargs) 

+

93 

+

94 def get_load_kwargs(self, **read_csv_kwargs: dict[str, Any]) -> dict[str, Any]: 

+

95 """Get kwargs for :py:meth:`~lymph.types.Model.load_patient_data`.""" 

+

96 return { 

+

97 "patient_data": self.load(**(read_csv_kwargs or {})), 

+

98 **self.model_dump(exclude={"source"}, exclude_none=True), 

+

99 } 

+

100 

+

101 

+

102def check_pattern(value: PatternType) -> Any: 

+

103 """Check if the value can be converted to a boolean value.""" 

+

104 return {lnl: map_to_optional_bool(v) for lnl, v in value.items()} 

+

105 

+

106 

+

107class DiagnosisConfig(BaseModel): 

+

108 """Defines an ipsi- and contralateral diagnosis pattern.""" 

+

109 

+

110 ipsi: dict[str, Annotated[PatternType, AfterValidator(check_pattern)]] = Field( 

+

111 default={}, 

+

112 description="Observed diagnoses by different modalities on the ipsi neck.", 

+

113 examples=[{"CT": {"II": True, "III": False}}], 

+

114 ) 

+

115 contra: dict[str, Annotated[PatternType, AfterValidator(check_pattern)]] = Field( 

+

116 default={}, 

+

117 description="Observed diagnoses by different modalities on the contra neck.", 

+

118 ) 

+

119 

+

120 def to_involvement(self, modality: str) -> InvolvementConfig: 

+

121 """Convert the diagnosis pattern to an involvement pattern for ``modality``.""" 

+

122 return InvolvementConfig( 

+

123 ipsi=self.ipsi.get(modality, {}), 

+

124 contra=self.contra.get(modality, {}), 

+

125 ) 

+

126 

+

127 

+

128class DistributionConfig(BaseModel): 

+

129 """Configuration defining a distribution over diagnose times.""" 

+

130 

+

131 kind: Literal["frozen", "parametric"] = Field( 

+

132 default="frozen", 

+

133 description="Parametric distributions may be updated.", 

+

134 ) 

+

135 func: FuncNameType = Field( 

+

136 default="binomial", 

+

137 description="Name of predefined function to use as distribution.", 

+

138 ) 

+

139 params: dict[str, int | float] = Field( 

+

140 default={}, 

+

141 description="Parameters to pass to the predefined function.", 

+

142 ) 

+

143 

+

144 

+

145class InvolvementConfig(BaseModel): 

+

146 """Config that defines an ipsi- and contralateral involvement pattern.""" 

+

147 

+

148 ipsi: Annotated[PatternType, AfterValidator(check_pattern)] = Field( 

+

149 default={}, 

+

150 description="Involvement pattern for the ipsilateral side of the neck.", 

+

151 examples=[{"II": True, "III": False}], 

+

152 ) 

+

153 contra: Annotated[PatternType, AfterValidator(check_pattern)] = Field( 

+

154 default={}, 

+

155 description="Involvement pattern for the contralateral side of the neck.", 

+

156 ) 

+

157 

+

158 

+

159def retrieve_graph_representation(model: Model) -> graph.Representation: 

+

160 """Retrieve the graph representation from a model.""" 

+

161 if hasattr(model, "graph"): 

+

162 return model.graph 

+

163 

+

164 if hasattr(model, "hpv"): 

+

165 return retrieve_graph_representation(model.hpv) 

+

166 

+

167 if hasattr(model, "ipsi"): 

+

168 return retrieve_graph_representation(model.ipsi) 

+

169 

+

170 if hasattr(model, "ext"): 

+

171 return retrieve_graph_representation(model.ext) 

+

172 

+

173 raise ValueError("Model does not have a graph representation.") 

+

174 

+

175 

+

176class GraphConfig(BaseModel): 

+

177 """Specifies how the tumor(s) and LNLs are connected in a DAG.""" 

+

178 

+

179 tumor: dict[str, list[str]] = Field( 

+

180 description="Define the name of the tumor(s) and which LNLs it/they drain to.", 

+

181 ) 

+

182 lnl: dict[str, list[str]] = Field( 

+

183 description="Define the name of the LNL(s) and which LNLs it/they drain to.", 

+

184 ) 

+

185 

+

186 @classmethod 

+

187 def from_model(cls: type, model: Model) -> GraphConfig: 

+

188 """Create a ``GraphConfig`` from a ``Model``.""" 

+

189 graph = retrieve_graph_representation(model) 

+

190 return cls( 

+

191 tumor={ 

+

192 name: [edge.child.name for edge in tumor.out] 

+

193 for name, tumor in graph.tumors.items() 

+

194 }, 

+

195 lnl={ 

+

196 name: [edge.child.name for edge in lnl.out] # noqa 

+

197 for name, lnl in graph.lnls.items() 

+

198 }, 

+

199 ) 

+

200 

+

201 

+

202def has_model_symbol(path: Path) -> Path: 

+

203 """Check if the Python file at ``path`` defines a symbol named ``model``.""" 

+

204 spec = importlib.util.spec_from_file_location(path.stem, path) 

+

205 module = importlib.util.module_from_spec(spec) 

+

206 spec.loader.exec_module(module) 

+

207 

+

208 if not hasattr(module, "model"): 

+

209 raise ValueError(f"Python file at {path} does not define a symbol 'model'.") 

+

210 

+

211 return path 

+

212 

+

213 

+

214def get_symmetry_kwargs(model: Model) -> dict[str, Any]: 

+

215 """Get the symmetry kwargs from a model.""" 

+

216 if isinstance(model, models.Unilateral | models.HPVUnilateral): 

+

217 raise TypeError("Unilateral models do not have symmetry kwargs.") 

+

218 

+

219 if hasattr(model, "ext"): 

+

220 return get_symmetry_kwargs(model.ext) 

+

221 

+

222 return getattr(model, "is_symmetric", {}) 

+

223 

+

224 

+

225class ModelConfig(BaseModel): 

+

226 """Define which of the ``lymph`` models to use and how to set them up.""" 

+

227 

+

228 external_file: Annotated[FilePath, AfterValidator(has_model_symbol)] | None = Field( 

+

229 default=None, 

+

230 description="Path to a Python file that defines a model.", 

+

231 ) 

+

232 class_name: Literal["Unilateral", "Bilateral", "Midline"] = Field( 

+

233 default="Unilateral", 

+

234 description="Name of the model class to use.", 

+

235 ) 

+

236 constructor: Literal["binary", "trinary"] = Field( 

+

237 default="binary", 

+

238 description="Trinary models differentiate btw. micro- and macroscopic disease.", 

+

239 ) 

+

240 max_time: int = Field( 

+

241 default=10, 

+

242 description="Max. number of time-steps to evolve the model over.", 

+

243 ) 

+

244 named_params: Sequence[str] = Field( 

+

245 default=None, 

+

246 description=( 

+

247 "Subset of valid model parameters a sampler may provide in the form of a " 

+

248 "dictionary to the model instead of as an array. Or, after sampling, with " 

+

249 "this list, one may safely recover which parameter corresponds to which " 

+

250 "index in the sample." 

+

251 ), 

+

252 ) 

+

253 kwargs: dict[str, Any] = Field( 

+

254 default={}, 

+

255 description="Additional keyword arguments to pass to the model constructor.", 

+

256 ) 

+

257 

+

258 @classmethod 

+

259 def from_model(cls: type, model: Model) -> ModelConfig: 

+

260 """Create a ``ModelConfig`` from a ``Model``.""" 

+

261 warnings.warn( 

+

262 message=( 

+

263 "Not all kwargs passed at initialization can be recovered into a " 

+

264 "config. Make sure to manually double-check the config." 

+

265 ), 

+

266 category=UserWarning, 

+

267 stacklevel=2, 

+

268 ) 

+

269 

+

270 if getattr(model, "_named_params", None): 

+

271 additional_kwargs = {"named_params": list(model.named_params)} 

+

272 else: 

+

273 additional_kwargs = {} 

+

274 

+

275 try: 

+

276 additional_kwargs["is_symmetric"] = get_symmetry_kwargs(model) 

+

277 except TypeError: 

+

278 pass 

+

279 

+

280 if isinstance(model, models.Midline): 

+

281 additional_kwargs["use_midext_evo"] = model.use_midext_evo 

+

282 additional_kwargs["use_central"] = hasattr(model, "_central") 

+

283 additional_kwargs["use_mixing"] = hasattr(model, "mixing_param") 

+

284 

+

285 if not hasattr(model, "_unknown"): 

+

286 additional_kwargs["marginalize_unknown"] = False 

+

287 

+

288 return cls( 

+

289 class_name=model.__class__.__name__, 

+

290 constructor="trinary" if model.is_trinary else "binary", 

+

291 max_time=model.max_time, 

+

292 kwargs=additional_kwargs, 

+

293 ) 

+

294 

+

295 

+

296def modalityconfig_from_model(model: Model, modality_name: str) -> ModalityConfig: 

+

297 """Create a ``ModalityConfig`` from a ``Model``.""" 

+

298 modality = model.get_modality(modality_name) 

+

299 return ModalityConfig( 

+

300 spec=modality.spec, 

+

301 sens=modality.sens, 

+

302 kind="pathological" if isinstance(modality, Pathological) else "clinical", 

+

303 ) 

+

304 

+

305 

+

306class DeprecatedModelConfig(BaseModel): 

+

307 """Model configuration prior to ``lyscripts`` major version 1. 

+

308 

+

309 This is implemented for backwards compatibility. Its sole job is to translate 

+

310 the outdated settings format into the new one. Note that the only stuff that needs 

+

311 to be translated is the model configuration itself and the distributions for 

+

312 marginalization over diagnosis times. The :py:class:`~GraphConfig` is still 

+

313 compatible. 

+

314 """ 

+

315 

+

316 first_binom_prob: float = Field( 

+

317 description="Fixed parameter for first binomial dist over diagnosis times.", 

+

318 ge=0.0, 

+

319 le=1.0, 

+

320 ) 

+

321 max_t: int = Field( 

+

322 description="Max. number of time-steps to evolve the model over.", 

+

323 gt=0, 

+

324 ) 

+

325 t_stages: list[int | str] = Field( 

+

326 description=( 

+

327 "List of T-stages to marginalize over in the scenario. The old format " 

+

328 "assumed all T-stages except the first one to be parametric. Only binomial " 

+

329 "distributions are supported." 

+

330 ), 

+

331 ) 

+

332 class_: Literal["Unilateral", "Bilateral", "Midline", "MidlineBilateral"] = Field( 

+

333 description="Name of the model class. Only binary models are supported.", 

+

334 alias="class", 

+

335 ) 

+

336 kwargs: dict[str, Any] = Field( 

+

337 default={}, 

+

338 description="Additional keyword arguments to pass to the model constructor.", 

+

339 ) 

+

340 

+

341 def model_post_init(self, __context): 

+

342 """Issue a deprecation warning.""" 

+

343 warnings.warn( 

+

344 message="The 'DeprecatedModelConfig' is deprecated.", 

+

345 category=DeprecationWarning, 

+

346 stacklevel=2, 

+

347 ) 

+

348 if "Midline" in self.class_: 

+

349 self.class_ = "Midline" 

+

350 warnings.warn( 

+

351 "Model may not be recreated as expected due to extra parameter " 

+

352 "`midext_prob`. Make sure to manually handle edge cases.", 

+

353 stacklevel=2, 

+

354 ) 

+

355 return super().model_post_init(__context) 

+

356 

+

357 def translate(self) -> tuple[ModelConfig, dict[int | str, DistributionConfig]]: 

+

358 """Translate the deprecated model config to the new format.""" 

+

359 old_kwargs = self.kwargs.copy() 

+

360 new_kwargs = {"use_midext_evo": False} if "Midline" in self.class_ else {} 

+

361 

+

362 if (tumor_spread := old_kwargs.pop("base_symmetric")) is not None: 

+

363 new_kwargs["is_symmetric"] = new_kwargs.get("is_symmetric", {}) 

+

364 new_kwargs["is_symmetric"]["tumor_spread"] = tumor_spread 

+

365 

+

366 if (lnl_spread := old_kwargs.pop("trans_symmetric")) is not None: 

+

367 new_kwargs["is_symmetric"] = new_kwargs.get("is_symmetric", {}) 

+

368 new_kwargs["is_symmetric"]["lnl_spread"] = lnl_spread 

+

369 

+

370 new_kwargs.update(old_kwargs) 

+

371 

+

372 model_config = ModelConfig( 

+

373 class_name=self.class_, 

+

374 constructor="binary", 

+

375 max_time=self.max_t, 

+

376 kwargs=new_kwargs, 

+

377 ) 

+

378 

+

379 distribution_configs = {} 

+

380 for i, t_stage in enumerate(self.t_stages): 

+

381 distribution_configs[t_stage] = DistributionConfig( 

+

382 kind="frozen" if i == 0 else "parametric", 

+

383 func="binomial", 

+

384 params={"p": self.first_binom_prob}, 

+

385 ) 

+

386 

+

387 return model_config, distribution_configs 

+

388 

+

389 

+

390class SamplingConfig(BaseModel): 

+

391 """Settings to configure the MCMC sampling.""" 

+

392 

+

393 storage_file: Path = Field( 

+

394 description="Path to HDF5 file store results or load last state.", 

+

395 ) 

+

396 history_file: Path | None = Field( 

+

397 default=None, 

+

398 description="Path to store the burn-in metrics (as CSV file).", 

+

399 ) 

+

400 dataset: str = Field( 

+

401 default="mcmc", 

+

402 description="Name of the dataset in the HDF5 file.", 

+

403 ) 

+

404 cores: int | None = Field( 

+

405 gt=0, 

+

406 default=os.cpu_count(), 

+

407 description=( 

+

408 "Number of cores to use for parallel sampling. If `None`, no parallel " 

+

409 "processing is used." 

+

410 ), 

+

411 ) 

+

412 seed: int = Field( 

+

413 default=42, 

+

414 description="Seed for the random number generator.", 

+

415 ) 

+

416 walkers_per_dim: int = Field( 

+

417 default=20, 

+

418 description="Number of walkers per parameter space dimension.", 

+

419 ) 

+

420 check_interval: int = Field( 

+

421 default=50, 

+

422 description="Check for convergence each time after this many steps.", 

+

423 ) 

+

424 trust_factor: float = Field( 

+

425 default=50.0, 

+

426 description=( 

+

427 "Trust the autocorrelation time only when it's smaller than this factor " 

+

428 "times the length of the chain." 

+

429 ), 

+

430 ) 

+

431 relative_thresh: float = Field( 

+

432 default=0.05, 

+

433 description="Relative threshold for convergence.", 

+

434 ) 

+

435 num_steps: int | None = Field( 

+

436 default=100, 

+

437 description=("Number of steps to take in the MCMC sampling."), 

+

438 ) 

+

439 thin_by: int = Field( 

+

440 default=10, 

+

441 description="How many samples to draw before for saving one.", 

+

442 ) 

+

443 inverse_temp: float = Field( 

+

444 default=1.0, 

+

445 description=( 

+

446 "Inverse temperature for thermodynamic integration. Note that this is not " 

+

447 "yet fully implemented." 

+

448 ), 

+

449 ) 

+

450 

+

451 def load(self, thin: int = 1) -> np.ndarray: 

+

452 """Load the samples from the HDF5 file. 

+

453 

+

454 Note that the ``thin`` represents another round of thinning and is usually 

+

455 not necessary if the samples were already thinned during the sampling process. 

+

456 """ 

+

457 return load_model_samples( 

+

458 file_path=self.storage_file, 

+

459 name=self.dataset, 

+

460 thin=thin, 

+

461 ) 

+

462 

+

463 

+

464def map_to_optional_bool(value: Any) -> Any: 

+

465 """Try to convert the options in the `PatternType` to a boolean value.""" 

+

466 if value in [True, "involved", 1]: 

+

467 return True 

+

468 

+

469 if value in [False, "healthy", 0]: 

+

470 return False 

+

471 

+

472 return value 

+

473 

+

474 

+

475class ScenarioConfig(BaseModel): 

+

476 """Define a scenario for which e.g. prevalences and risks may be computed.""" 

+

477 

+

478 t_stages: list[int | str] = Field( 

+

479 description="List of T-stages to marginalize over in the scenario.", 

+

480 examples=[["early"], [3, 4]], 

+

481 ) 

+

482 t_stages_dist: list[float] = Field( 

+

483 default=[1.0], 

+

484 description="Distribution over T-stages to use for marginalization.", 

+

485 examples=[[1.0], [0.6, 0.4]], 

+

486 ) 

+

487 midext: bool | None = Field( 

+

488 default=None, 

+

489 description="Whether the patient's tumor extends over the midline.", 

+

490 ) 

+

491 mode: Literal["HMM", "BN"] = Field( 

+

492 default="HMM", 

+

493 description="Which underlying model architecture to use.", 

+

494 ) 

+

495 involvement: InvolvementConfig = InvolvementConfig() 

+

496 diagnosis: DiagnosisConfig = DiagnosisConfig() 

+

497 

+

498 def model_post_init(self, __context: Any) -> None: 

+

499 """Interpolate and normalize the distribution.""" 

+

500 self.interpolate() 

+

501 self.normalize() 

+

502 

+

503 def interpolate(self): 

+

504 """Interpolate the distribution to the number of ``t_stages``.""" 

+

505 if len(self.t_stages) != len(self.t_stages_dist): 

+

506 new_x = np.linspace(0.0, 1.0, len(self.t_stages)) 

+

507 old_x = np.linspace(0.0, 1.0, len(self.t_stages_dist)) 

+

508 # cast to list to make ``__eq__`` work 

+

509 self.t_stages_dist = np.interp(new_x, old_x, self.t_stages_dist).tolist() 

+

510 

+

511 def normalize(self): 

+

512 """Normalize the distribution to sum to 1.""" 

+

513 if not np.isclose(np.sum(self.t_stages_dist), 1.0): 

+

514 self.t_stages_dist = ( 

+

515 np.array(self.t_stages_dist) / np.sum(self.t_stages_dist) 

+

516 ).tolist() # cast to list to make ``__eq__`` work 

+

517 

+

518 

+

519def _construct_model_from_external(path: Path) -> Model: 

+

520 """Construct a model from a Python file.""" 

+

521 module_name = path.stem 

+

522 spec = importlib.util.spec_from_file_location(module_name, path) 

+

523 module = importlib.util.module_from_spec(spec) 

+

524 spec.loader.exec_module(module) 

+

525 logger.info(f"Loaded model from {path}. This ignores model and graph configs.") 

+

526 return module.model 

+

527 

+

528 

+

529def construct_model( 

+

530 model_config: ModelConfig, 

+

531 graph_config: GraphConfig, 

+

532) -> Model: 

+

533 """Construct a model from a ``model_config``. 

+

534 

+

535 The default/expected use of this is to specify a model class from the 

+

536 `lymph`_ package and pass the necessary arguments to its constructor. 

+

537 However, it is also possible to load a model from an external Python file via the 

+

538 ``external`` attribute of the ``model_config`` argument. In this case, a symbol 

+

539 with name ``model`` must be defined in the file that is to be loaded. 

+

540 

+

541 .. note:: 

+

542 

+

543 No check is performed on the model's compatibility with the command/pipeline 

+

544 it is used in. It is assumed the model complies with the 

+

545 :py:class:`model type <lymph.types.Model>` specifications of the `lymph`_ 

+

546 package. 

+

547 

+

548 .. _lymph: https://lymph-model.readthedocs.io/stable/ 

+

549 """ 

+

550 if model_config.external_file is not None: 

+

551 return _construct_model_from_external(model_config.external_file) 

+

552 

+

553 cls = getattr(models, model_config.class_name) 

+

554 constructor = getattr(cls, model_config.constructor) 

+

555 model = constructor( 

+

556 graph_dict=flatten(graph_config.model_dump()), 

+

557 max_time=model_config.max_time, 

+

558 named_params=model_config.named_params, 

+

559 **model_config.kwargs, 

+

560 ) 

+

561 logger.info(f"Constructed model: {model}") 

+

562 return model 

+

563 

+

564 

+

565def add_distributions( 

+

566 model: Model, 

+

567 configs: dict[str | int, DistributionConfig], 

+

568 mapping: dict[FuncNameType, Callable] | None = None, 

+

569 inplace: bool = False, 

+

570) -> Model: 

+

571 """Construct and add distributions over diagnose times to a ``model``.""" 

+

572 if not inplace: 

+

573 model = deepcopy(model) 

+

574 logger.debug("Created deepcopy of model.") 

+

575 

+

576 mapping = mapping or DIST_MAP 

+

577 

+

578 for t_stage, dist_config in configs.items(): 

+

579 if dist_config.kind == "frozen": 

+

580 support = np.arange(model.max_time + 1) 

+

581 dist = mapping[dist_config.func](support, **dist_config.params) 

+

582 elif dist_config.kind == "parametric": 

+

583 dist = mapping[dist_config.func] 

+

584 else: 

+

585 raise ValueError(f"Unknown distribution kind: {dist_config.kind}") 

+

586 

+

587 model.set_distribution(t_stage, dist) 

+

588 if dist_config.kind == "parametric" and dist_config.params: 

+

589 params = {f"{t_stage}_{k}": v for k, v in dist_config.params.items()} 

+

590 model.set_params(**params) 

+

591 

+

592 logger.debug(f"Set {dist_config.kind} distribution for '{t_stage}': {dist}") 

+

593 

+

594 logger.info(f"Added {len(configs)} distributions to model: {model}") 

+

595 return model 

+

596 

+

597 

+

598def add_modalities( 

+

599 model: Model, 

+

600 modalities: dict[str, ModalityConfig], 

+

601 inplace: bool = False, 

+

602) -> Model: 

+

603 """Add ``modalities`` to a ``model``.""" 

+

604 if not inplace: 

+

605 model = deepcopy(model) 

+

606 logger.debug("Created deepcopy of model.") 

+

607 

+

608 for modality, modality_config in modalities.items(): 

+

609 model.set_modality(modality, **modality_config.model_dump()) 

+

610 logger.debug(f"Added modality {modality} to model: {modality_config}") 

+

611 

+

612 logger.info(f"Added {len(modalities)} modalities to model: {model}") 

+

613 return model 

+

614 

+

615 

+

616def add_data( 

+

617 model: Model, 

+

618 path: Path, 

+

619 side: Literal["ipsi", "contra"], 

+

620 mapping: dict[Literal[0, 1, 2, 3, 4], int | str] | None = None, 

+

621 inplace: bool = False, 

+

622) -> Model: 

+

623 """Add data to a ``model``.""" 

+

624 data = pd.read_csv(path, header=[0, 1, 2]) 

+

625 logger.debug(f"Loaded data from {path}: Shape: {data.shape}") 

+

626 

+

627 kwargs = {"patient_data": data, "mapping": mapping} 

+

628 if isinstance(model, models.Unilateral): 

+

629 kwargs["side"] = side 

+

630 

+

631 if not inplace: 

+

632 model = deepcopy(model) 

+

633 logger.debug("Created deepcopy of model.") 

+

634 

+

635 model.load_patient_data(**kwargs) 

+

636 logger.info(f"Added data to model: {model}") 

+

637 return model 

+

638 

+

639 

+

640PathType = Path | str | Sequence[Path | str] 

+

641 

+

642 

+

643class DynamicYamlConfigSettingsSource(YamlConfigSettingsSource): 

+

644 """YAML config source that allows dynamic file path specification. 

+

645 

+

646 This is heavily inspired by `this comment`_ in the discussion on a related issue 

+

647 of the `pydantic-settings`_ GitHub repository. 

+

648 

+

649 Essentially, this little hack allows a user to specify a one or multiple YAML files 

+

650 from which the CLI should read configurations. Normally, `pydantic-settings` only 

+

651 allows hard-coding the location of these config files. 

+

652 

+

653 .. _this comment: https://github.com/pydantic/pydantic-settings/issues/259#issuecomment-2549444286 

+

654 .. _pydantic-settings: https://github.com/pydantic/pydantic-settings 

+

655 """ 

+

656 

+

657 def __init__( 

+

658 self, 

+

659 settings_cls, 

+

660 yaml_file: PathType | None = DEFAULT_PATH, 

+

661 yaml_file_encoding: str | None = None, 

+

662 yaml_file_path_field: str = "configs", 

+

663 ) -> None: 

+

664 """Allow getting the YAML file path from any key in the current state. 

+

665 

+

666 The argument ``yaml_file_path_field`` should be the :py:class:`BaseSettings` 

+

667 field that contains the path(s) to the YAML file(s). 

+

668 

+

669 Note that all config files must have a ``version: 1`` key in them to be 

+

670 recognized as valid config files. 

+

671 """ 

+

672 self.yaml_file_path_field = yaml_file_path_field 

+

673 super().__init__(settings_cls, yaml_file, yaml_file_encoding) 

+

674 

+

675 def _read_file(self, file_path: Path) -> dict[str, Any]: 

+

676 """Read the YAML and raise exception when ``version: 1`` not found.""" 

+

677 with open(file_path, encoding=self.yaml_file_encoding) as yaml_file: 

+

678 data = yaml.safe_load(yaml_file) or {} 

+

679 if data.get("version") != 1: 

+

680 raise ValueError( 

+

681 f"Config file {file_path} does not have a 'version: 1' key. " 

+

682 "For compatibility reasons, all config files must have this key.", 

+

683 ) 

+

684 return data 

+

685 

+

686 def __call__(self) -> dict[str, Any]: 

+

687 """Reload the config files from the paths in the current state.""" 

+

688 yaml_file_to_reload = self.current_state.get( 

+

689 self.yaml_file_path_field, 

+

690 self.yaml_file_path, 

+

691 ) 

+

692 logger.debug(f"Reloading YAML files from {yaml_file_to_reload} (if it exists).") 

+

693 self.__init__( 

+

694 settings_cls=self.settings_cls, 

+

695 yaml_file=yaml_file_to_reload, 

+

696 yaml_file_encoding=self.yaml_file_encoding, 

+

697 yaml_file_path_field=self.yaml_file_path_field, 

+

698 ) 

+

699 return super().__call__() 

+

700 

+

701 def __repr__(self) -> str: 

+

702 """Return a string representation of the source.""" 

+

703 return ( 

+

704 self.__class__.__name__ 

+

705 + "(" 

+

706 + f"yaml_file={self.yaml_file_path!r}, " 

+

707 + f"yaml_file_encoding={self.yaml_file_encoding!r}, " 

+

708 + f"yaml_file_path_field={self.yaml_file_path_field!r}" 

+

709 + ")" 

+

710 ) 

+

711 

+

712 

+

713class BaseCLI(BaseSettings): 

+

714 """Base settings class for all CLI scripts to inherit from.""" 

+

715 

+

716 model_config = ConfigDict(yaml_file="config.yaml", extra="ignore") 

+

717 

+

718 configs: list[Path] = Field( 

+

719 default=["config.yaml"], 

+

720 description=( 

+

721 "Path to the YAML file(s) that contain the configuration(s). Configs from " 

+

722 "YAML files may be overwritten by command line arguments. When multiple " 

+

723 "files are specified, the configs are merged in the order they are given. " 

+

724 "Note that every config file must have a `version: 1` key in it." 

+

725 ), 

+

726 ) 

+

727 

+

728 @classmethod 

+

729 def settings_customise_sources( 

+

730 cls, 

+

731 settings_cls: type[BaseSettings], 

+

732 init_settings: PydanticBaseSettingsSource, 

+

733 env_settings: PydanticBaseSettingsSource, 

+

734 dotenv_settings: PydanticBaseSettingsSource, 

+

735 file_secret_settings: PydanticBaseSettingsSource, 

+

736 ) -> tuple[PydanticBaseSettingsSource, ...]: 

+

737 """Add the dynamic YAML config source to the CLI settings.""" 

+

738 dynamic_yaml_config_source = DynamicYamlConfigSettingsSource( 

+

739 settings_cls=settings_cls, 

+

740 yaml_file_path_field="configs", 

+

741 yaml_file_encoding="utf-8", 

+

742 ) 

+

743 logger.debug(f"Created {dynamic_yaml_config_source = }") 

+

744 return ( 

+

745 init_settings, 

+

746 env_settings, 

+

747 dotenv_settings, 

+

748 file_secret_settings, 

+

749 dynamic_yaml_config_source, 

+

750 ) 

+
+ + + diff --git a/htmlcov/z_5bf5c588c698c6cc_decorators_py.html b/htmlcov/z_5bf5c588c698c6cc_decorators_py.html new file mode 100644 index 0000000..35c5565 --- /dev/null +++ b/htmlcov/z_5bf5c588c698c6cc_decorators_py.html @@ -0,0 +1,185 @@ + + + + + Coverage for src/lyscripts/decorators.py: 90% + + + + + +
+
+

+ Coverage for src/lyscripts/decorators.py: + 90% +

+ +

+ 41 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Decorators to avoid repetitive snippets of code. 

+

2 

+

3E.g. safely opening files or logging the state of a function call. 

+

4 

+

5This is *not* a command line tool. 

+

6""" 

+

7 

+

8import functools 

+

9import logging 

+

10from collections.abc import Callable 

+

11from functools import wraps 

+

12from pathlib import Path 

+

13from typing import Any 

+

14 

+

15 

+

16def assemble_signature(*args, **kwargs) -> str: 

+

17 """Assemble the signature of the function call.""" 

+

18 args_str = ", ".join(str(arg) for arg in args) 

+

19 kwargs_str = ", ".join(f"{key}={value}" for key, value in kwargs.items()) 

+

20 return ", ".join([args_str, kwargs_str]) 

+

21 

+

22 

+

23def log_state(log_level: int = logging.INFO) -> Callable: 

+

24 """Provide a decorator that logs the state of the function execution. 

+

25 

+

26 The log message will simply be the function name where underscores are replaced 

+

27 with spaces. The `log_level` can be set in the decorator call. 

+

28 """ 

+

29 

+

30 def log_decorator(func: Callable): 

+

31 """Decorate function for which to add logs.""" 

+

32 

+

33 @functools.wraps(func) 

+

34 def wrapper(*args, **kwargs): 

+

35 """Execute decorated function.""" 

+

36 logger = logging.getLogger(func.__module__) 

+

37 signature = assemble_signature(*args, **kwargs) 

+

38 logger.debug(f"Executing {func.__name__}({signature}).") 

+

39 log_msg_from_func = func.__name__.replace("_", " ").capitalize() + "." 

+

40 

+

41 try: 

+

42 logger.log( 

+

43 log_level, 

+

44 log_msg_from_func, 

+

45 extra={ 

+

46 "func_filepath": f"{func.__module__.replace('.', '/')}.py", 

+

47 "func_name": func.__name__, 

+

48 "module_name": func.__module__, 

+

49 }, 

+

50 ) 

+

51 return func(*args, **kwargs) 

+

52 

+

53 except Exception as exc: 

+

54 logger.error(f"Error calling {func.__name__}().", exc_info=exc) 

+

55 raise exc 

+

56 

+

57 return wrapper 

+

58 

+

59 return log_decorator 

+

60 

+

61 

+

62def check_input_file_exists(loading_func: Callable) -> Callable: 

+

63 """Check if the file path provided to the `loading_func` exists.""" 

+

64 

+

65 @wraps(loading_func) 

+

66 def inner(file_path: str, *args, **kwargs) -> Any: 

+

67 """Execute wrapped loading function.""" 

+

68 file_path = Path(file_path) 

+

69 if not file_path.is_file(): 

+

70 raise FileNotFoundError(f"File {file_path} does not exist.") 

+

71 

+

72 return loading_func(file_path, *args, **kwargs) 

+

73 

+

74 return inner 

+

75 

+

76 

+

77def check_output_dir_exists(saving_func: Callable) -> Callable: 

+

78 """Make sure the parent directory of the saved file exists.""" 

+

79 

+

80 @wraps(saving_func) 

+

81 def inner(file_path: str, *args, **kwargs) -> Any: 

+

82 """Execute wrapped saving function.""" 

+

83 file_path = Path(file_path) 

+

84 file_path.parent.mkdir(parents=True, exist_ok=True) 

+

85 

+

86 return saving_func(file_path, *args, **kwargs) 

+

87 

+

88 return inner 

+
+ + + diff --git a/htmlcov/z_5bf5c588c698c6cc_evaluate_py.html b/htmlcov/z_5bf5c588c698c6cc_evaluate_py.html new file mode 100644 index 0000000..85cd60a --- /dev/null +++ b/htmlcov/z_5bf5c588c698c6cc_evaluate_py.html @@ -0,0 +1,309 @@ + + + + + Coverage for src/lyscripts/evaluate.py: 24% + + + + + +
+
+

+ Coverage for src/lyscripts/evaluate.py: + 24% +

+ +

+ 75 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Evaluate the performance of the trained model. 

+

2 

+

3This is done by computing quantities like the Bayesian information criterion (BIC) or 

+

4(if thermodynamic integration was performed) the actual evidence (with error) of the 

+

5model. 

+

6""" 

+

7 

+

8import argparse 

+

9import json 

+

10from pathlib import Path 

+

11 

+

12import emcee 

+

13import h5py 

+

14import numpy as np 

+

15import pandas as pd 

+

16from loguru import logger 

+

17from scipy.integrate import trapezoid 

+

18 

+

19from lyscripts.utils import load_patient_data, load_yaml_params 

+

20 

+

21RNG = np.random.default_rng() 

+

22 

+

23 

+

24def _add_parser( 

+

25 subparsers: argparse._SubParsersAction, 

+

26 help_formatter, 

+

27): 

+

28 """Add an ``ArgumentParser`` to the subparsers action.""" 

+

29 parser = subparsers.add_parser( 

+

30 Path(__file__).name.replace(".py", ""), 

+

31 description=__doc__, 

+

32 help=__doc__, 

+

33 formatter_class=help_formatter, 

+

34 ) 

+

35 _add_arguments(parser) 

+

36 

+

37 

+

38def _add_arguments(parser: argparse.ArgumentParser): 

+

39 """Add arguments to a ``subparsers`` instance and run its main function when chosen. 

+

40 

+

41 This is called by the parent module that is called via the command line. 

+

42 """ 

+

43 parser.add_argument( 

+

44 "data", 

+

45 type=Path, 

+

46 help="Path to the tables of patient data (CSV).", 

+

47 ) 

+

48 parser.add_argument("model", type=Path, help="Path to model output files (HDF5).") 

+

49 

+

50 parser.add_argument( 

+

51 "-p", 

+

52 "--params", 

+

53 default="./params.yaml", 

+

54 type=Path, 

+

55 help="Path to parameter file", 

+

56 ) 

+

57 parser.add_argument( 

+

58 "--plots", 

+

59 default="./plots", 

+

60 type=Path, 

+

61 help="Directory for storing plots", 

+

62 ) 

+

63 parser.add_argument( 

+

64 "--metrics", 

+

65 default="./metrics.json", 

+

66 type=Path, 

+

67 help="Path to metrics file", 

+

68 ) 

+

69 

+

70 parser.set_defaults(run_main=main) 

+

71 

+

72 

+

73def comp_bic(log_probs: np.ndarray, num_params: int, num_data: int) -> float: 

+

74 r"""Compute the negative one half of the Bayesian Information Criterion (BIC). 

+

75 

+

76 The BIC is defined as [^1] 

+

77 $$ BIC = k \\ln{n} - 2 \\ln{\\hat{L}} $$ 

+

78 where $k$ is the number of parameters ``num_params``, $n$ the number of datapoints 

+

79 ``num_data`` and $\\hat{L}$ the maximum likelihood estimate of the ``log_prob``. 

+

80 It is constructed such that the following is an 

+

81 approximation of the model evidence: 

+

82 $$ p(D \\mid m) \\approx \\exp{\\left( - BIC / 2 \\right)} $$ 

+

83 which is why this function returns the negative one half of it. 

+

84 

+

85 [^1]: https://en.wikipedia.org/wiki/Bayesian_information_criterion 

+

86 """ 

+

87 return np.max(log_probs) - num_params * np.log(num_data) / 2.0 

+

88 

+

89 

+

90def compute_evidence( 

+

91 temp_schedule: np.ndarray, 

+

92 log_probs: np.ndarray, 

+

93 num: int = 1000, 

+

94) -> tuple[float, float]: 

+

95 """Compute the evidence and its standard deviation. 

+

96 

+

97 Given a ``temp_schedule`` of inverse temperatures and corresponding sets of 

+

98 ``log_probs``, draw ``num`` "paths" of log-probabilities and compute the evidence 

+

99 for each using trapezoidal integration. 

+

100 

+

101 The evidence is then the mean of those ``num`` integrations, while the error is 

+

102 their standard deviation. 

+

103 """ 

+

104 integrals = np.zeros(shape=num) 

+

105 for i in range(num): 

+

106 rand_idx = RNG.choice(log_probs.shape[1], size=log_probs.shape[0]) 

+

107 drawn_accuracy = log_probs[np.arange(log_probs.shape[0]), rand_idx].copy() 

+

108 integrals[i] = trapezoid(y=drawn_accuracy, x=temp_schedule) 

+

109 return np.mean(integrals), np.std(integrals) 

+

110 

+

111 

+

112def compute_ti_results( 

+

113 metrics: dict, 

+

114 params: dict, 

+

115 ndim: int, 

+

116 h5_file: Path, 

+

117 model: Path, 

+

118) -> tuple[np.ndarray, np.ndarray]: 

+

119 """Compute the results in case of a thermodynamic integration run.""" 

+

120 temp_schedule = params["sampling"]["temp_schedule"] 

+

121 num_temps = len(temp_schedule) 

+

122 

+

123 if num_temps != len(h5_file["ti"]): 

+

124 raise RuntimeError( 

+

125 f"Parameters suggest temp schedule of length {num_temps}, " 

+

126 f"but stored are {len(h5_file['ti'])}", 

+

127 ) 

+

128 

+

129 nwalker = ndim * params["sampling"]["walkers_per_dim"] 

+

130 nsteps = params["sampling"]["nsteps"] 

+

131 ti_log_probs = np.zeros(shape=(num_temps, nsteps * nwalker)) 

+

132 

+

133 for i, run in enumerate(h5_file["ti"]): 

+

134 reader = emcee.backends.HDFBackend(model, name=f"ti/{run}", read_only=True) 

+

135 ti_log_probs[i] = reader.get_blobs(flat=True) 

+

136 

+

137 evidence, evidence_std = compute_evidence(temp_schedule, ti_log_probs) 

+

138 metrics["evidence"] = evidence 

+

139 metrics["evidence_std"] = evidence_std 

+

140 

+

141 return temp_schedule, ti_log_probs 

+

142 

+

143 

+

144def main(args: argparse.Namespace): 

+

145 """Run main script.""" 

+

146 metrics = {} 

+

147 

+

148 params = load_yaml_params(args.params) 

+

149 model = None # create_model(params) 

+

150 ndim = len(model.get_params()) 

+

151 data = load_patient_data(args.data) 

+

152 h5_file = h5py.File(args.model, mode="r") 

+

153 

+

154 # if TI has been performed, compute the accuracy for every step 

+

155 if "ti" in h5_file: 

+

156 temp_schedule, ti_log_probs = compute_ti_results( 

+

157 metrics=metrics, 

+

158 params=params, 

+

159 ndim=ndim, 

+

160 h5_file=h5_file, 

+

161 model=args.model, 

+

162 ) 

+

163 logger.info( 

+

164 "Computed results of thermodynamic integration with " 

+

165 f"{len(temp_schedule)} steps", 

+

166 ) 

+

167 

+

168 # store inverse temperatures and log-probs in CSV file 

+

169 args.plots.parent.mkdir(exist_ok=True) 

+

170 

+

171 beta_vs_accuracy = pd.DataFrame( 

+

172 np.array( 

+

173 [ 

+

174 temp_schedule, 

+

175 np.mean(ti_log_probs, axis=1), 

+

176 np.std(ti_log_probs, axis=1), 

+

177 ], 

+

178 ).T, 

+

179 columns=["β", "accuracy", "std"], 

+

180 ) 

+

181 beta_vs_accuracy.to_csv(args.plots, index=False) 

+

182 logger.info(f"Plotted β vs accuracy at {args.plots}") 

+

183 

+

184 # use blobs, because also for TI, this is the unscaled log-prob 

+

185 backend = emcee.backends.HDFBackend(args.model, read_only=True, name="mcmc") 

+

186 final_log_probs = backend.get_blobs() 

+

187 logger.info(f"Opened samples from emcee backend from {args.model}") 

+

188 

+

189 # store metrics in JSON file 

+

190 args.metrics.parent.mkdir(parents=True, exist_ok=True) 

+

191 args.metrics.touch(exist_ok=True) 

+

192 

+

193 metrics["BIC"] = comp_bic( 

+

194 final_log_probs, 

+

195 ndim, 

+

196 len(data), 

+

197 ) 

+

198 metrics["max_llh"] = np.max(final_log_probs) 

+

199 metrics["mean_llh"] = np.mean(final_log_probs) 

+

200 

+

201 with open(args.metrics, mode="w", encoding="utf-8") as metrics_file: 

+

202 json.dump(metrics, metrics_file) 

+

203 

+

204 logger.info(f"Wrote out metrics to {args.metrics}") 

+

205 

+

206 

+

207if __name__ == "__main__": 

+

208 parser = argparse.ArgumentParser(description=__doc__) 

+

209 _add_arguments(parser) 

+

210 

+

211 args = parser.parse_args() 

+

212 args.run_main(args) 

+
+ + + diff --git a/htmlcov/z_5bf5c588c698c6cc_plots_py.html b/htmlcov/z_5bf5c588c698c6cc_plots_py.html new file mode 100644 index 0000000..5dce988 --- /dev/null +++ b/htmlcov/z_5bf5c588c698c6cc_plots_py.html @@ -0,0 +1,508 @@ + + + + + Coverage for src/lyscripts/plots.py: 86% + + + + + +
+
+

+ Coverage for src/lyscripts/plots.py: + 86% +

+ +

+ 166 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Utility functions for the plotting commands.""" 

+

2 

+

3from __future__ import annotations 

+

4 

+

5from abc import abstractmethod 

+

6from collections.abc import Mapping 

+

7from dataclasses import field 

+

8from itertools import cycle 

+

9from pathlib import Path 

+

10from typing import TYPE_CHECKING, Any, TypeVar 

+

11 

+

12import h5py 

+

13import matplotlib.pyplot as plt 

+

14import numpy as np 

+

15import scipy as sp 

+

16from numpydantic import NDArray, Shape 

+

17from pydantic import BaseModel 

+

18 

+

19from lyscripts.decorators import ( 

+

20 check_input_file_exists, 

+

21 check_output_dir_exists, 

+

22 log_state, 

+

23) 

+

24 

+

25if TYPE_CHECKING: 

+

26 from matplotlib.axes._axes import Axes as MPLAxes 

+

27 from matplotlib.figure import Figure 

+

28 

+

29# define USZ colors 

+

30COLORS = { 

+

31 "blue": "#005ea8", 

+

32 "orange": "#f17900", 

+

33 "green": "#00afa5", 

+

34 "red": "#ae0060", 

+

35 "gray": "#c5d5db", 

+

36} 

+

37COLOR_CYCLE = cycle(COLORS.values()) 

+

38CM_PER_INCH = 2.54 

+

39 

+

40 

+

41def floor_at_decimal(value: float, decimal: int) -> float: 

+

42 """Compute the floor of ``value`` for the specified ``decimal``. 

+

43 

+

44 Essentially the distance to the right of the decimal point. May be negative. 

+

45 """ 

+

46 power = 10**decimal 

+

47 return np.floor(power * value) / power 

+

48 

+

49 

+

50def ceil_at_decimal(value: float, decimal: int) -> float: 

+

51 """Compute the ceiling of ``value`` for the specified ``decimal``. 

+

52 

+

53 Analog to :py:func:`.floor_at_decimal`, this is the distance to the right of the 

+

54 decimal point. May be negative. 

+

55 """ 

+

56 return -floor_at_decimal(-value, decimal) 

+

57 

+

58 

+

59def floor_to_step(value: float, step: float) -> float: 

+

60 """Compute next value on ladder of stepsize ``step`` still below ``value``.""" 

+

61 return (value // step) * step 

+

62 

+

63 

+

64def ceil_to_step(value: float, step: float) -> float: 

+

65 """Compute next value on ladder of stepsize ``step`` still above ``value``.""" 

+

66 return floor_to_step(value, step) + step 

+

67 

+

68 

+

69def clean_and_check(filename: str | Path) -> Path: 

+

70 """Check if file with ``filename`` exists. 

+

71 

+

72 If not, raise error, otherwise return cleaned :py:class:`~pathlib.PosixPath`. 

+

73 """ 

+

74 filepath = Path(filename) 

+

75 if not filepath.exists(): 

+

76 msg = f"File with the name {filename} does not exist at {filepath.resolve()}" 

+

77 raise FileNotFoundError(msg) 

+

78 return filepath 

+

79 

+

80 

+

81AbstractDistributionT = TypeVar("AbstractDistributionT", bound="AbstractDistribution") 

+

82 

+

83 

+

84class AbstractDistribution(BaseModel): 

+

85 """Abstract class for distributions that should be plotted.""" 

+

86 

+

87 scale: float = 100.0 

+

88 offset: float = 0.0 

+

89 kwargs: dict[str, Any] = field(default_factory=lambda: {}) 

+

90 

+

91 @abstractmethod 

+

92 def draw(self, axes: MPLAxes) -> MPLAxes: 

+

93 """Draw the distribution into the provided ``axes``.""" 

+

94 ... 

+

95 

+

96 @abstractmethod 

+

97 def left_percentile(self, percent: float) -> float: 

+

98 """Compute the point where ``percent`` of the values are to the left.""" 

+

99 ... 

+

100 

+

101 @abstractmethod 

+

102 def right_percentile(self, percent: float) -> float: 

+

103 """Compute the point where ``percent`` of the values are to the right.""" 

+

104 ... 

+

105 

+

106 def _get_label(self) -> str: 

+

107 """Compute label for when ``kwargs`` does not contain one.""" 

+

108 

+

109 @property 

+

110 def label(self) -> str: 

+

111 """Return the label of the histogram.""" 

+

112 return self.kwargs.get("label", self._get_label()) 

+

113 

+

114 

+

115class Histogram(AbstractDistribution): 

+

116 """Class containing data for plotting a histogram.""" 

+

117 

+

118 raw_values: NDArray[Shape["*"], float] # noqa: F722 

+

119 

+

120 @property 

+

121 def values(self) -> np.ndarray: 

+

122 """Return the values of the histogram scaled and offset.""" 

+

123 return self.raw_values * self.scale + self.offset 

+

124 

+

125 @classmethod 

+

126 def from_hdf5( 

+

127 cls: type[Histogram], 

+

128 filename: str | Path, 

+

129 dataname: str, 

+

130 scale: float = 100.0, 

+

131 offset: float = 0.0, 

+

132 **kwargs, 

+

133 ) -> Histogram: 

+

134 """Create a histogram from an HDF5 file.""" 

+

135 filename = clean_and_check(filename) 

+

136 with h5py.File(filename, mode="r") as h5file: 

+

137 dataset = h5file[dataname] 

+

138 if "label" not in kwargs: 

+

139 kwargs["label"] = get_label(dataset.attrs) 

+

140 return cls(raw_values=dataset[:], scale=scale, offset=offset, kwargs=kwargs) 

+

141 

+

142 def left_percentile(self, percent: float) -> float: 

+

143 """Compute the point where `percent` of the values are to the left.""" 

+

144 return np.percentile(self.values, percent) 

+

145 

+

146 def right_percentile(self, percent: float) -> float: 

+

147 """Compute the point where `percent` of the values are to the right.""" 

+

148 return np.percentile(self.values, 100.0 - percent) 

+

149 

+

150 def draw(self, axes: MPLAxes, **defaults) -> Any: 

+

151 """Draw the histogram into the provided ``axes``.""" 

+

152 xlim = axes.get_xlim() 

+

153 

+

154 hist_kwargs = defaults.get("hist", {}).copy() 

+

155 hist_kwargs.update(self.kwargs) 

+

156 

+

157 if self.label is not None: 

+

158 hist_kwargs["label"] = self.label 

+

159 

+

160 return axes.hist(self.values, range=xlim, **hist_kwargs) 

+

161 

+

162 

+

163class BetaPosterior(AbstractDistribution): 

+

164 """Class for storing plot configs for a Beta posterior.""" 

+

165 

+

166 num_success: int 

+

167 num_total: int 

+

168 

+

169 @classmethod 

+

170 def from_hdf5( 

+

171 cls: type[BetaPosterior], 

+

172 filename: str | Path, 

+

173 dataname: str, 

+

174 scale: float = 100.0, 

+

175 offset: float = 0.0, 

+

176 **kwargs, 

+

177 ) -> BetaPosterior: 

+

178 """Initialize data container for Beta posteriors from HDF5 file.""" 

+

179 filename = clean_and_check(filename) 

+

180 with h5py.File(filename, mode="r") as h5file: 

+

181 dataset = h5file[dataname] 

+

182 try: 

+

183 num_success = int(dataset.attrs["num_match"]) 

+

184 num_total = int(dataset.attrs["num_total"]) 

+

185 except KeyError as key_err: 

+

186 raise KeyError( 

+

187 "Dataset does not contain observed prevalence data", 

+

188 ) from key_err 

+

189 

+

190 return cls( 

+

191 num_success=num_success, 

+

192 num_total=num_total, 

+

193 scale=scale, 

+

194 offset=offset, 

+

195 kwargs=kwargs, 

+

196 ) 

+

197 

+

198 def _get_label(self) -> str: 

+

199 return f"data: {self.num_success} of {self.num_total}" 

+

200 

+

201 @property 

+

202 def num_fail(self): 

+

203 """Return the number of failures, i.e. the totals minus the successes.""" 

+

204 return self.num_total - self.num_success 

+

205 

+

206 def pdf(self, x: np.ndarray) -> np.ndarray: 

+

207 """Compute the probability density function.""" 

+

208 return sp.stats.beta.pdf( 

+

209 x, 

+

210 a=self.num_success + 1, 

+

211 b=self.num_fail + 1, 

+

212 loc=self.offset, 

+

213 scale=self.scale, 

+

214 ) 

+

215 

+

216 def left_percentile(self, percent: float) -> float: 

+

217 """Return the point where the CDF reaches ``percent``.""" 

+

218 return sp.stats.beta.ppf( 

+

219 percent / 100.0, 

+

220 a=self.num_success + 1, 

+

221 b=self.num_fail + 1, 

+

222 scale=self.scale, 

+

223 ) 

+

224 

+

225 def right_percentile(self, percent: float) -> float: 

+

226 """Return the point where 100% minus the CDF equals ``percent``.""" 

+

227 return sp.stats.beta.ppf( 

+

228 1.0 - (percent / 100.0), 

+

229 a=self.num_success + 1, 

+

230 b=self.num_fail + 1, 

+

231 scale=self.scale, 

+

232 ) 

+

233 

+

234 def draw(self, axes: MPLAxes, resolution: int = 300, **defaults) -> Any: 

+

235 """Draw the Beta posterior into the provided ``axes``. 

+

236 

+

237 Returns a handle and a label for the legend. 

+

238 """ 

+

239 left, right = axes.get_xlim() 

+

240 x = np.linspace(left, right, resolution) 

+

241 y = self.pdf(x) 

+

242 

+

243 plot_kwargs = defaults.get("plot", {}).copy() 

+

244 plot_kwargs.update(self.kwargs) 

+

245 

+

246 if self.label is not None: 

+

247 plot_kwargs["label"] = self.label 

+

248 

+

249 return axes.plot(x, y, **plot_kwargs) 

+

250 

+

251 

+

252def get_size(width="single", unit="cm", ratio="golden"): 

+

253 """Return a tuple of figure sizes in inches. 

+

254 

+

255 This is provided as the ``matplotlib`` keyword argument ``figsize`` expects it. 

+

256 This figure size is computed from a ``width``, in the ``unit`` of centimeters by 

+

257 default, and a ``ratio`` which is set to the golden ratio by default. 

+

258 

+

259 >>> get_size(width="single", ratio="golden") 

+

260 (3.937007874015748, 2.4332557935820445) 

+

261 >>> get_size(width="full", ratio=2.) 

+

262 (6.299212598425196, 3.149606299212598) 

+

263 >>> get_size(width=10., ratio=1.) 

+

264 (3.937007874015748, 3.937007874015748) 

+

265 >>> get_size(width=5, unit="inches", ratio=2./3.) 

+

266 (5, 7.5) 

+

267 """ 

+

268 if width == "single": 

+

269 width = 10 

+

270 elif width == "full": 

+

271 width = 16 

+

272 

+

273 ratio = 1.618 if ratio == "golden" else ratio 

+

274 width = width / CM_PER_INCH if unit == "cm" else width 

+

275 height = width / ratio 

+

276 return (width, height) 

+

277 

+

278 

+

279def get_label(attrs: Mapping) -> str: 

+

280 """Extract label of a histogram from the HDF5 ``attrs`` object of the dataset.""" 

+

281 label = [] 

+

282 transforms = { 

+

283 "label": str, 

+

284 "modality": str, 

+

285 "t_stage": str, 

+

286 "midline_ext": lambda x: "ext" if x else "noext", 

+

287 } 

+

288 for key, func in transforms.items(): 

+

289 if key in attrs and attrs[key] is not None: 

+

290 label.append(func(attrs[key])) 

+

291 return " | ".join(label) 

+

292 

+

293 

+

294def get_xlims( 

+

295 contents: AbstractDistributionT, 

+

296 percent_lims: tuple[float] = (10.0, 10.0), 

+

297) -> tuple[float]: 

+

298 """Get the x-axis limits for a plot containing multiple distribution. 

+

299 

+

300 Compute the ``xlims`` of a plot containing histograms and probability density 

+

301 functions by considering their smallest and largest percentiles. 

+

302 """ 

+

303 left_percentiles = np.array( 

+

304 [c.left_percentile(percent_lims[0]) for c in contents], 

+

305 ) 

+

306 left_lim = np.min(left_percentiles) 

+

307 right_percentiles = np.array( 

+

308 [c.right_percentile(percent_lims[0]) for c in contents], 

+

309 ) 

+

310 right_lim = np.max(right_percentiles) 

+

311 return left_lim, right_lim 

+

312 

+

313 

+

314def draw( 

+

315 axes: MPLAxes, 

+

316 contents: list[AbstractDistribution], 

+

317 percent_lims: tuple[float, float] = (10.0, 10.0), 

+

318 xlims: tuple[float] | None = None, 

+

319 hist_kwargs: dict[str, Any] | None = None, 

+

320 plot_kwargs: dict[str, Any] | None = None, 

+

321) -> MPLAxes: 

+

322 """Draw histograms and Beta posterior from ``contents`` into ``axes``. 

+

323 

+

324 The limits of the x-axis is computed to be the smallest and largest left and right 

+

325 percentile of all provided ``contents`` respectively via the ``percent_lims`` tuple. 

+

326 

+

327 The ``hist_kwargs`` define general settings that will be applied to all histograms. 

+

328 One additional key ``'nbins'`` may be used to adjust only the numbers, not the 

+

329 spacing of the histogram bins. 

+

330 Similarly, ``plot_kwargs`` adjusts the default settings for the Beta posteriors. 

+

331 

+

332 Both these keyword arguments can be overwritten by what the individual ``contents`` 

+

333 have defined. 

+

334 """ 

+

335 if not all(isinstance(c, AbstractDistribution) for c in contents): 

+

336 raise TypeError("Contents must be subclasses of `AbstractDistribution`") 

+

337 

+

338 xlims = xlims or get_xlims(contents, percent_lims) 

+

339 

+

340 if len(xlims) != 2 or xlims[0] > xlims[-1]: 

+

341 raise ValueError("`xlims` must be tuple of two increasing values") 

+

342 

+

343 axes.set_xlim(*xlims) 

+

344 

+

345 default_kwargs = { 

+

346 "hist": { 

+

347 "density": True, 

+

348 "histtype": "stepfilled", 

+

349 "alpha": 0.7, 

+

350 "bins": 50, 

+

351 }, 

+

352 "plot": {}, 

+

353 } 

+

354 default_kwargs["hist"].update(hist_kwargs or {}) 

+

355 default_kwargs["plot"].update(plot_kwargs or {}) 

+

356 

+

357 for content in contents: 

+

358 content.draw(axes, **default_kwargs) 

+

359 

+

360 return axes 

+

361 

+

362 

+

363def split_legends( 

+

364 axes: MPLAxes, 

+

365 titles: list[str], 

+

366 locs: list[tuple[float, float]], 

+

367 **kwargs, 

+

368) -> None: 

+

369 """Separate labels in ``axes`` into separate legends with ``titles`` at ``locs``.""" 

+

370 legend_kwargs = { 

+

371 "title_fontsize": "small", 

+

372 "labelspacing": 0.1, 

+

373 "loc": "upper left", 

+

374 } 

+

375 legend_kwargs.update(kwargs) 

+

376 

+

377 handles, labels = axes.get_legend_handles_labels() 

+

378 labels_per_legend = len(labels) // len(titles) 

+

379 

+

380 for i, (title, loc) in enumerate(zip(titles, locs, strict=True)): 

+

381 start = i * labels_per_legend 

+

382 stop = (i + 1) * labels_per_legend if i < len(titles) - 1 else None 

+

383 idx = slice(start, stop) 

+

384 

+

385 legend = axes.legend( 

+

386 handles[idx], 

+

387 labels[idx], 

+

388 bbox_to_anchor=loc, 

+

389 title=title, 

+

390 **legend_kwargs, 

+

391 ) 

+

392 axes.add_artist(legend) 

+

393 

+

394 

+

395@log_state() 

+

396@check_input_file_exists 

+

397def use_mpl_stylesheet(file_path: str | Path): 

+

398 """Load a ``.mplstyle`` stylesheet from ``file_path``.""" 

+

399 plt.style.use(file_path) 

+

400 

+

401 

+

402@log_state() 

+

403@check_output_dir_exists 

+

404def save_figure( 

+

405 output_path: str | Path, 

+

406 figure: Figure, 

+

407 formats: list[str] | None, 

+

408): 

+

409 """Save a ``figure`` to ``output_path`` in every one of the provided ``formats``.""" 

+

410 for frmt in formats: 

+

411 figure.savefig(output_path.with_suffix(f".{frmt}")) 

+
+ + + diff --git a/htmlcov/z_5bf5c588c698c6cc_sample_py.html b/htmlcov/z_5bf5c588c698c6cc_sample_py.html new file mode 100644 index 0000000..fc32eec --- /dev/null +++ b/htmlcov/z_5bf5c588c698c6cc_sample_py.html @@ -0,0 +1,518 @@ + + + + + Coverage for src/lyscripts/sample.py: 92% + + + + + +
+
+

+ Coverage for src/lyscripts/sample.py: + 92% +

+ +

+ 136 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Implementation of flexible MCMC sampling for lymphatic progression models. 

+

2 

+

3This module provides both helpful functions for programmatically building and running 

+

4sampling pipelines, as well a CLI interface for th most common sampling use cases. 

+

5 

+

6The core is the :py:func:`run_sampling` function. It has a flexible interface and 

+

7built-in convergence detection, as well as bookkeeping for monitoring and resuming 

+

8interrupted sampling runs. It can be used both during the burn-in phase and the actual 

+

9sampling phase. 

+

10 

+

11.. warning:: 

+

12 

+

13 We strongly recommend to set the CLI's ``--cores`` argument to ``None`` (or ``null`` 

+

14 in the YAML config file) if you are on MacOS or Windows. This is because we haven't 

+

15 yet figured out how we can safely and efficiently use the ``multiprocess(ing)`` 

+

16 library on these two platforms. 

+

17""" 

+

18 

+

19from __future__ import annotations 

+

20 

+

21import os 

+

22import sys 

+

23from typing import Any 

+

24 

+

25from loguru import logger 

+

26 

+

27from lyscripts.cli import assemble_main 

+

28 

+

29try: 

+

30 import multiprocess as mp 

+

31except ModuleNotFoundError: 

+

32 import multiprocessing as mp 

+

33 

+

34if sys.platform == "darwin": 

+

35 logger.warning("Detected MacOS. Setting multiprocess(ing) start method to 'fork'.") 

+

36 mp.set_start_method("fork") 

+

37 

+

38from pathlib import Path 

+

39 

+

40import emcee 

+

41import numpy as np 

+

42import pandas as pd 

+

43from lydata.utils import ModalityConfig 

+

44from lymph.types import ParamsType 

+

45from pydantic import BaseModel, Field 

+

46from rich.progress import Progress, ProgressColumn, Task, TimeElapsedColumn 

+

47from rich.text import Text 

+

48 

+

49from lyscripts.configs import ( 

+

50 BaseCLI, 

+

51 DataConfig, 

+

52 DistributionConfig, 

+

53 GraphConfig, 

+

54 ModelConfig, 

+

55 SamplingConfig, 

+

56 add_distributions, 

+

57 add_modalities, 

+

58 construct_model, 

+

59) 

+

60from lyscripts.utils import console, get_hdf5_backend 

+

61 

+

62 

+

63class CompletedItersColumn(ProgressColumn): 

+

64 """A column that displays the completed number of iterations.""" 

+

65 

+

66 def __init__(self, table_column=None, it: int = 0): 

+

67 """Initialize the column with number of previous iterations.""" 

+

68 super().__init__(table_column) 

+

69 self.it = it 

+

70 

+

71 def render(self, task: Task) -> Text: 

+

72 """Render total iterations.""" 

+

73 if task.completed is None: 

+

74 return Text("? it", style="progress.data.steps") 

+

75 return Text(f"{task.completed + self.it} it", style="progress.data.steps") 

+

76 

+

77 

+

78class ItersPerSecondColumn(ProgressColumn): 

+

79 """A column that displays the number of iterations per second.""" 

+

80 

+

81 def render(self, task: Task) -> Text: 

+

82 """Render iterations per second.""" 

+

83 speed = task.finished_speed or task.speed 

+

84 if speed is None: 

+

85 return Text("? it/s", style="progress.data.speed") 

+

86 return Text(f"{speed:.2f} it/s", style="progress.data.speed") 

+

87 

+

88 

+

89class AcorTime(BaseModel, validate_assignment=True): 

+

90 """Storage for old and new autocorrelation times.""" 

+

91 

+

92 old: float 

+

93 new: float 

+

94 

+

95 def update(self, new: float) -> None: 

+

96 """Update the autocorrelation time.""" 

+

97 self.old = self.new 

+

98 self.new = new 

+

99 

+

100 @property 

+

101 def relative_diff(self) -> float: 

+

102 """Get the relative difference between new and old autocorrelation time.""" 

+

103 return np.abs(self.new - self.old) / self.new 

+

104 

+

105 

+

106class NumAccepted(BaseModel, validate_assignment=True): 

+

107 """Storage for old and new number of accepted proposals.""" 

+

108 

+

109 old: int 

+

110 new: int 

+

111 

+

112 def update(self, new: int) -> None: 

+

113 """Update the number of accepted proposals.""" 

+

114 self.old = self.new 

+

115 self.new = new 

+

116 

+

117 @property 

+

118 def newly_accepted(self) -> int: 

+

119 """Get the number of newly accepted proposals.""" 

+

120 return self.new - self.old 

+

121 

+

122 

+

123MODEL = None 

+

124 

+

125 

+

126def log_prob_fn(theta: ParamsType, inverse_temp: float = 1.0) -> tuple[float, float]: 

+

127 """Compute log-prob using global variables because of pickling. 

+

128 

+

129 An inverse temperature ``inverse_temp`` can be provided for thermodynamic 

+

130 integration. 

+

131 """ 

+

132 return inverse_temp * MODEL.likelihood(given_params=theta), inverse_temp 

+

133 

+

134 

+

135def ensure_initial_state(sampler: emcee.EnsembleSampler) -> np.ndarray: 

+

136 """Try to extract a starting state from a ``sampler``. 

+

137 

+

138 Create a random starting state if no one was found. 

+

139 """ 

+

140 try: 

+

141 state = sampler.backend.get_last_sample() 

+

142 logger.info( 

+

143 f"Resuming from {sampler.backend.filename} with {sampler.iteration} " 

+

144 "stored iterations.", 

+

145 ) 

+

146 except AttributeError: 

+

147 state = np.random.uniform(size=(sampler.nwalkers, sampler.ndim)) # noqa: NPY002 

+

148 logger.debug(f"No stored samples found. Starting from random state {state}.") 

+

149 

+

150 return state 

+

151 

+

152 

+

153def ensure_history_table(file: Path | None) -> pd.DataFrame: 

+

154 """Return the history table from a file or an empty DataFrame. 

+

155 

+

156 It will try to load a history at the given ``file`` location, but with a ``.tmp`` 

+

157 extension. This is the expected name and location of a history file that was 

+

158 stored during an interrupted sampling run. 

+

159 

+

160 If no file is found, an empty DataFrame is returned. 

+

161 """ 

+

162 if file is None or not file.with_suffix(".tmp").exists(): 

+

163 return pd.DataFrame( 

+

164 columns=[ 

+

165 "steps", 

+

166 "acor_times", 

+

167 "accept_fracs", 

+

168 "max_log_probs", 

+

169 ], 

+

170 ).set_index("steps") 

+

171 

+

172 return pd.read_csv(file.with_suffix(".tmp"), index_col="steps") 

+

173 

+

174 

+

175def update_history_table( 

+

176 history: pd.DataFrame, 

+

177 history_file: Path | None, 

+

178 iteration: int, 

+

179 acor_time: float, 

+

180 accepted_frac: float, 

+

181 max_log_prob: float, 

+

182) -> pd.DataFrame: 

+

183 """Update the history table with the current iteration's information.""" 

+

184 history.loc[iteration] = [acor_time, accepted_frac, max_log_prob] 

+

185 logger.debug(history.iloc[-1].to_dict()) 

+

186 

+

187 if history_file is not None: 

+

188 history.to_csv(history_file.with_suffix(".tmp")) 

+

189 

+

190 return history 

+

191 

+

192 

+

193def is_converged( 

+

194 iteration: int, 

+

195 acor_time: AcorTime, 

+

196 trust_factor: float, 

+

197 relative_thresh: float, 

+

198) -> bool: 

+

199 """Check if the chain has converged based on the autocorrelation time. 

+

200 

+

201 The criterion is based on the relative change of the autocorrelation time and 

+

202 whether the autocorrelation extimate can be trusted. Essentially, we only trust 

+

203 the estimate if it is smaller than ``trust_factor`` times the current ``iteration``. 

+

204 

+

205 More details can be found in the `emcee documentation`_. 

+

206 

+

207 .. _emcee documentation: https://emcee.readthedocs.io/en/stable/tutorials/autocorr/ 

+

208 """ 

+

209 return ( 

+

210 acor_time.new * trust_factor < iteration 

+

211 and acor_time.relative_diff < relative_thresh 

+

212 ) 

+

213 

+

214 

+

215def _get_columns(it: int = 0) -> list[ProgressColumn]: 

+

216 """Get the default progress columns for the MCMC sampling.""" 

+

217 return [ 

+

218 *Progress.get_default_columns(), 

+

219 ItersPerSecondColumn(), 

+

220 CompletedItersColumn(it=it), 

+

221 TimeElapsedColumn(), 

+

222 ] 

+

223 

+

224 

+

225def run_sampling( 

+

226 sampler: emcee.EnsembleSampler, 

+

227 initial_state: np.ndarray | None = None, 

+

228 num_steps: int | None = None, 

+

229 thin_by: int = 1, 

+

230 check_interval: int = 100, 

+

231 trust_factor: float = 50.0, 

+

232 relative_thresh: float = 0.05, 

+

233 history_file: Path | None = None, 

+

234 reset_backend: bool = False, 

+

235 description: str = "Burn-in phase", 

+

236) -> None: 

+

237 """Run MCMC sampling. 

+

238 

+

239 This will run the ``sampler`` either for ``num_steps`` steps or - if it set to 

+

240 ``None`` - until convergence. Convergence is determined once within a 

+

241 ``check_interval`` of steps by the :py:func:`is_converged` function. The 

+

242 convergence criterion is based on a trustworthy estimate of the autocorrelation 

+

243 time. This is elaborated in the `emcee documentation`_. 

+

244 

+

245 Some bookkeeping parameters may be stored in a ``history_file``. During sampling, 

+

246 the history is stored in a temporary file with the suffix ``.tmp``. If the sampling 

+

247 is interrupted, the history and the last state of the ``sampler`` can be recovered 

+

248 and the sampling can be continued. 

+

249 

+

250 One may choose to ``reset_backend``, e.g. in case the previous sampling was run 

+

251 until convergence and now one wants to store a length of the converged chain. This 

+

252 may also be thinned by a factor of ``thin_by`` (directly passed to the 

+

253 :py:class:`emcee.EnsembleSampler` class). 

+

254 

+

255 .. _emcee documentation: https://emcee.readthedocs.io/en/stable/tutorials/autocorr/ 

+

256 """ 

+

257 state = initial_state or ensure_initial_state(sampler) 

+

258 history = ensure_history_table(history_file) 

+

259 

+

260 if reset_backend: 

+

261 logger.debug("Resetting backend of sampler.") 

+

262 sampler.backend.reset(sampler.nwalkers, sampler.ndim) 

+

263 

+

264 acor_time = AcorTime(old=np.inf, new=np.inf) 

+

265 accepted = NumAccepted(old=0, new=sampler.backend.accepted.sum()) 

+

266 

+

267 with Progress(*_get_columns(it=sampler.iteration), console=console) as progress: 

+

268 task = progress.add_task(description=description, total=num_steps) 

+

269 while sampler.iteration < (num_steps or np.inf): 

+

270 for state in sampler.sample( # noqa: B007, B020 

+

271 initial_state=state, 

+

272 iterations=check_interval - sampler.iteration % check_interval, 

+

273 thin_by=thin_by, 

+

274 ): 

+

275 progress.update(task, advance=1) 

+

276 

+

277 acor_time.update(new=sampler.get_autocorr_time(tol=0).mean()) 

+

278 accepted.update(new=sampler.backend.accepted.sum()) 

+

279 

+

280 history = update_history_table( 

+

281 history=history, 

+

282 history_file=history_file, 

+

283 iteration=sampler.iteration, 

+

284 acor_time=acor_time.new, 

+

285 accepted_frac=( 

+

286 accepted.newly_accepted / (check_interval * sampler.nwalkers) 

+

287 ), 

+

288 max_log_prob=np.max(state.log_prob), 

+

289 ) 

+

290 

+

291 if num_steps is None and is_converged( 

+

292 iteration=sampler.iteration, 

+

293 acor_time=acor_time, 

+

294 trust_factor=trust_factor, 

+

295 relative_thresh=relative_thresh, 

+

296 ): 

+

297 logger.info(f"Sampling converged after {sampler.iteration} steps.") 

+

298 break 

+

299 

+

300 if history_file is not None: 

+

301 history_file.with_suffix(".tmp").rename(history_file) 

+

302 

+

303 

+

304class DummyPool: 

+

305 """Dummy class to allow for no multiprocessing.""" 

+

306 

+

307 def __enter__(self) -> None: 

+

308 """Enter the context manager.""" 

+

309 ... 

+

310 

+

311 def __exit__(self, *args) -> None: 

+

312 """Exit the context manager.""" 

+

313 ... 

+

314 

+

315 

+

316def get_pool(num_cores: int | None) -> Any | DummyPool: # type: ignore 

+

317 """Get a ``multiprocess(ing)`` pool or ``DummyPool``. 

+

318 

+

319 Returns a ``multiprocess(ing)`` pool with ``num_cores`` cores if ``num_cores`` is 

+

320 not ``None``. Otherwise, a ``DummyPool`` is returned. 

+

321 """ 

+

322 return mp.Pool(num_cores) if num_cores is not None else DummyPool() 

+

323 

+

324 

+

325def init_sampler(settings: SampleCLI, ndim: int, pool: Any) -> emcee.EnsembleSampler: 

+

326 """Initialize the ``emcee.EnsembleSampler`` with the given ``settings``.""" 

+

327 nwalkers = ndim * settings.sampling.walkers_per_dim 

+

328 backend = get_hdf5_backend( 

+

329 file_path=settings.sampling.storage_file, 

+

330 dataset=settings.sampling.dataset, 

+

331 nwalkers=nwalkers, 

+

332 ndim=ndim, 

+

333 ) 

+

334 return emcee.EnsembleSampler( 

+

335 nwalkers=nwalkers, 

+

336 ndim=ndim, 

+

337 log_prob_fn=log_prob_fn, 

+

338 kwargs={"inverse_temp": settings.sampling.inverse_temp}, 

+

339 moves=[(emcee.moves.DEMove(), 0.8), (emcee.moves.DESnookerMove(), 0.2)], 

+

340 backend=backend, 

+

341 pool=pool, 

+

342 blobs_dtype=[("inverse_temp", np.float64)], 

+

343 parameter_names=list(MODEL.get_named_params().keys()), 

+

344 ) 

+

345 

+

346 

+

347class SampleCLI(BaseCLI): 

+

348 """Use MCMC to infer distributions over model parameters from data.""" 

+

349 

+

350 graph: GraphConfig 

+

351 model: ModelConfig = ModelConfig() 

+

352 distributions: dict[str, DistributionConfig] = Field( 

+

353 default={}, 

+

354 description=( 

+

355 "Mapping of model T-categories to predefined distributions over " 

+

356 "diagnose times." 

+

357 ), 

+

358 ) 

+

359 modalities: dict[str, ModalityConfig] = Field( 

+

360 default={}, 

+

361 description=( 

+

362 "Maps names of diagnostic modalities to their specificity/sensitivity." 

+

363 ), 

+

364 ) 

+

365 data: DataConfig 

+

366 sampling: SamplingConfig 

+

367 

+

368 def cli_cmd(self) -> None: 

+

369 """Start the ``sample`` subcommand. 

+

370 

+

371 First, it will construct the model from the ``graph`` and ``model`` arguments. 

+

372 Then, it will add distributions over diagnose times via the dictionary from 

+

373 the ``distributions`` argument. It will also set sensitivity and specificity of 

+

374 diagnostic modalities via the dictionary provided through the ``modalities`` 

+

375 argument. Finally, it will load the patient data as specified via the ``data`` 

+

376 argument. 

+

377 

+

378 When the model is constructed, an :py:class:`emcee.EnsembleSampler` is 

+

379 initialized (see :py:func:`init_sampler`) and :py:func:`run_sampling` is 

+

380 executed twice: once for the burn-in phase and once for the actual sampling 

+

381 phase. The ``sampling`` argument provides all necessary settings for the 

+

382 sampling. 

+

383 """ 

+

384 # as recommended in https://emcee.readthedocs.io/en/stable/tutorials/parallel/# 

+

385 os.environ["OMP_NUM_THREADS"] = "1" 

+

386 

+

387 logger.debug(self.model_dump_json(indent=2)) 

+

388 

+

389 # ugly, but necessary for pickling 

+

390 global MODEL 

+

391 MODEL = construct_model(self.model, self.graph) 

+

392 MODEL = add_distributions(MODEL, self.distributions) 

+

393 MODEL = add_modalities(MODEL, self.modalities) 

+

394 MODEL.load_patient_data(**self.data.get_load_kwargs()) 

+

395 ndim = MODEL.get_num_dims() 

+

396 

+

397 # emcee does not support numpy's new random number generator yet. 

+

398 np.random.seed(self.sampling.seed) # noqa: NPY002 

+

399 

+

400 with get_pool(self.sampling.cores) as pool: 

+

401 sampler = init_sampler(settings=self, ndim=ndim, pool=pool) 

+

402 run_sampling( 

+

403 description="Burn-in phase", 

+

404 sampler=sampler, 

+

405 check_interval=self.sampling.check_interval, 

+

406 trust_factor=self.sampling.trust_factor, 

+

407 relative_thresh=self.sampling.relative_thresh, 

+

408 history_file=self.sampling.history_file, 

+

409 ) 

+

410 run_sampling( 

+

411 description="Sampling phase", 

+

412 sampler=sampler, 

+

413 num_steps=self.sampling.num_steps, 

+

414 reset_backend=True, 

+

415 thin_by=self.sampling.thin_by, 

+

416 ) 

+

417 

+

418 

+

419if __name__ == "__main__": 

+

420 main = assemble_main(settings_cls=SampleCLI, prog_name="sample") 

+

421 main() 

+
+ + + diff --git a/htmlcov/z_5bf5c588c698c6cc_schedule_py.html b/htmlcov/z_5bf5c588c698c6cc_schedule_py.html new file mode 100644 index 0000000..14f05ef --- /dev/null +++ b/htmlcov/z_5bf5c588c698c6cc_schedule_py.html @@ -0,0 +1,182 @@ + + + + + Coverage for src/lyscripts/schedule.py: 55% + + + + + +
+
+

+ Coverage for src/lyscripts/schedule.py: + 55% +

+ +

+ 29 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1r"""Generate inverse temperature schedules for thermodynamic integration. 

+

2 

+

3Thermodynamic integration is quite sensitive to the specific schedule which is used. 

+

4I noticed in my models, that within the interval :math:`[0, 0.1]`, the increase in the 

+

5expected log-likelihood is very steep. Hence, the inverse temperature :math:`\beta` 

+

6must be more densely spaced in the beginning. 

+

7 

+

8This can be achieved by using a power sequence: Generate :math:`n` linearly spaced 

+

9points in the interval :math:`[0, 1]` and then transform each point by computing 

+

10:math:`\beta_i^k` where :math:`k` could e.g. be 5. 

+

11""" 

+

12 

+

13from typing import Literal 

+

14 

+

15import numpy as np 

+

16from loguru import logger 

+

17from pydantic import Field 

+

18 

+

19from lyscripts.cli import assemble_main 

+

20from lyscripts.configs import BaseCLI 

+

21 

+

22 

+

23def geometric_schedule(num: int, *_a) -> np.ndarray: 

+

24 """Create a geometric sequence of ``num`` numbers from 0 to 1.""" 

+

25 log_seq = np.logspace(0.0, 1.0, num) 

+

26 shifted_seq = log_seq - 1.0 

+

27 return shifted_seq / 9.0 

+

28 

+

29 

+

30def linear_schedule(num: int, *_a) -> np.ndarray: 

+

31 """Create a linear sequence of ``num`` numbers from 0 to 1. 

+

32 

+

33 Equivalent to the :py:func:`power_schedule` with ``power=1``. 

+

34 """ 

+

35 return np.linspace(0.0, 1.0, num) 

+

36 

+

37 

+

38def power_schedule(num: int, power: float, *_a) -> np.ndarray: 

+

39 """Create a power sequence of ``num`` numbers from 0 to 1. 

+

40 

+

41 This is essentially a :py:func:`linear_schedule` of ``num`` numbers from 0 to 1, 

+

42 but each number is raised to the power of ``power``. 

+

43 """ 

+

44 lin_seq = np.linspace(0.0, 1.0, num) 

+

45 return lin_seq**power 

+

46 

+

47 

+

48SCHEDULES = { 

+

49 "geometric": geometric_schedule, 

+

50 "linear": linear_schedule, 

+

51 "power": power_schedule, 

+

52} 

+

53 

+

54 

+

55class ScheduleCLI(BaseCLI): 

+

56 """Generate an inverse temperature schedule for thermodynamic integration.""" 

+

57 

+

58 method: Literal["geometric", "linear", "power"] = Field( 

+

59 default="geometric", 

+

60 description="Choose the method to distribute the inverse temperatures.", 

+

61 ) 

+

62 num: int = Field( 

+

63 default=32, 

+

64 description="Number of inverse temperatures in the schedule.", 

+

65 ) 

+

66 power: float = Field( 

+

67 default=4, 

+

68 description="If a power schedule is chosen, use this as power.", 

+

69 ) 

+

70 

+

71 def cli_cmd(self) -> None: 

+

72 """Start the ``schedule`` command.""" 

+

73 logger.debug(self.model_dump_json(indent=2)) 

+

74 

+

75 func = SCHEDULES[self.method] 

+

76 schedule = func(self.num, self.power) 

+

77 

+

78 for inv_temp in schedule: 

+

79 # print is necessary to allow piping the output 

+

80 print(inv_temp) # noqa: T201 

+

81 

+

82 

+

83if __name__ == "__main__": 

+

84 main = assemble_main(settings_cls=ScheduleCLI, prog_name="schedule") 

+

85 main() 

+
+ + + diff --git a/htmlcov/z_5bf5c588c698c6cc_schema_py.html b/htmlcov/z_5bf5c588c698c6cc_schema_py.html new file mode 100644 index 0000000..315ac04 --- /dev/null +++ b/htmlcov/z_5bf5c588c698c6cc_schema_py.html @@ -0,0 +1,162 @@ + + + + + Coverage for src/lyscripts/schema.py: 86% + + + + + +
+
+

+ Coverage for src/lyscripts/schema.py: + 86% +

+ +

+ 21 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""A fusion of all :py:mod:`configs`, allowing the creation of a JSON schema. 

+

2 

+

3This command is not intended to be used by the end user. Rather, it exists such that 

+

4the developers and maintainers can create a JSON schema from all the defined 

+

5:py:mod:`configs` an store that in the `source code repository`_. Subsequently, the 

+

6end user can point their IDE to this schema, hosted on GitHub to provide them with 

+

7auto-completion and validation of their YAML configuration files that they feed into 

+

8the lyscripts CLIs when they build pipelines or scripts with it. 

+

9 

+

10The `URL for the schema`_ can for example be used in the settings of VS Code like this: 

+

11 

+

12.. code:: json 

+

13 

+

14 { 

+

15 "yaml.schemas": { 

+

16 "https://raw.githubusercontent.com/lycosystem/lyscripts/main/schemas/ly.json": "*.ly.yaml" 

+

17 }, 

+

18 } 

+

19 

+

20Which would enable auto-completion and validation for all files with the extension 

+

21``.ly.yaml`` in the workspace. 

+

22 

+

23.. _source code repository: https://github.com/lycosystem/lyscripts 

+

24.. _URL for the schema: https://raw.githubusercontent.com/lycosystem/lyscripts/main/schemas/ly.json 

+

25""" # noqa: E501 

+

26 

+

27import json 

+

28 

+

29from lydata.utils import ModalityConfig 

+

30from pydantic import BaseModel, Field 

+

31 

+

32from lyscripts import configs 

+

33 

+

34 

+

35class SchemaSettings(BaseModel): 

+

36 """Settings for generating a JSON schema for lyscripts configuration files.""" 

+

37 

+

38 version: int = Field( 

+

39 description=( 

+

40 "For future compatibility reasons, every config file must have a " 

+

41 "`version: 1` field at the top level." 

+

42 ), 

+

43 ge=1, 

+

44 le=1, 

+

45 ) 

+

46 cross_validation: configs.CrossValidationConfig = None 

+

47 data: configs.DataConfig = None 

+

48 diagnosis: configs.DiagnosisConfig = None 

+

49 distributions: dict[str, configs.DistributionConfig] = {} 

+

50 graph: configs.GraphConfig = None 

+

51 involvement: configs.InvolvementConfig = None 

+

52 modalities: dict[str, ModalityConfig] = {} 

+

53 model: configs.ModelConfig = None 

+

54 sampling: configs.SamplingConfig = None 

+

55 scenarios: list[configs.ScenarioConfig] = [] 

+

56 

+

57 

+

58def main() -> None: 

+

59 """Generate a JSON schema for lyscripts configuration files.""" 

+

60 schema = SchemaSettings.model_json_schema() 

+

61 print(json.dumps(schema, indent=2)) # noqa: T201 

+

62 

+

63 

+

64if __name__ == "__main__": 

+

65 main() 

+
+ + + diff --git a/htmlcov/z_5bf5c588c698c6cc_utils_py.html b/htmlcov/z_5bf5c588c698c6cc_utils_py.html new file mode 100644 index 0000000..a95cac5 --- /dev/null +++ b/htmlcov/z_5bf5c588c698c6cc_utils_py.html @@ -0,0 +1,296 @@ + + + + + Coverage for src/lyscripts/utils.py: 94% + + + + + +
+
+

+ Coverage for src/lyscripts/utils.py: + 94% +

+ +

+ 84 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""General utility functions for the lyscripts package.""" 

+

2 

+

3from pathlib import Path 

+

4 

+

5import numpy as np 

+

6import pandas as pd 

+

7import yaml 

+

8from emcee.backends import HDFBackend 

+

9from loguru import logger 

+

10from rich.console import Console 

+

11from scipy.special import factorial 

+

12 

+

13from lyscripts.decorators import ( 

+

14 check_input_file_exists, 

+

15 check_output_dir_exists, 

+

16) 

+

17 

+

18console = Console() 

+

19 

+

20 

+

21def binom_pmf(support: list[int] | np.ndarray, p: float = 0.5): 

+

22 """Binomial PMF that is much faster than the one from scipy.""" 

+

23 max_time = len(support) - 1 

+

24 if p > 1.0 or p < 0.0: 

+

25 raise ValueError("Binomial prob must be btw. 0 and 1") 

+

26 q = 1.0 - p 

+

27 binom_coeff = factorial(max_time) / ( 

+

28 factorial(support) * factorial(max_time - support) 

+

29 ) 

+

30 return binom_coeff * p**support * q ** (max_time - support) 

+

31 

+

32 

+

33def get_dict_depth(nested: dict) -> int: 

+

34 """Get the depth of a nested dictionary. 

+

35 

+

36 >>> get_dict_depth({"a": {"b": 1}}) 

+

37 2 

+

38 >>> varying_depth = {"a": {"b": 1}, "c": {"d": {"e": 2}}} 

+

39 >>> get_dict_depth(varying_depth) 

+

40 3 

+

41 """ 

+

42 if not isinstance(nested, dict): 

+

43 return 0 

+

44 

+

45 max_depth = None 

+

46 for _, value in nested.items(): 

+

47 value_depth = get_dict_depth(value) 

+

48 max_depth = max(max_depth or value_depth, value_depth) 

+

49 

+

50 return 1 + (max_depth or 0) 

+

51 

+

52 

+

53def delete_private_keys(nested: dict) -> dict: 

+

54 """Delete private keys from a nested dictionary. 

+

55 

+

56 A 'private' key is a key whose name starts with an underscore. For example: 

+

57 

+

58 >>> delete_private_keys({"patient": {"__doc__": "some patient info", "age": 61}}) 

+

59 {'patient': {'age': 61}} 

+

60 >>> delete_private_keys({"patient": {"age": 61}}) 

+

61 {'patient': {'age': 61}} 

+

62 """ 

+

63 cleaned = {} 

+

64 

+

65 if isinstance(nested, dict): 

+

66 for key, value in nested.items(): 

+

67 if not (isinstance(key, str) and key.startswith("_")): 

+

68 cleaned[key] = delete_private_keys(value) 

+

69 else: 

+

70 cleaned = nested 

+

71 

+

72 return cleaned 

+

73 

+

74 

+

75def flatten( 

+

76 nested: dict, 

+

77 prev_key: tuple = (), 

+

78 max_depth: int | None = None, 

+

79) -> dict: 

+

80 """Flatten ``nested`` dict by creating key tuples for each value at ``max_depth``. 

+

81 

+

82 >>> nested = {"tumor": {"1": {"t_stage": 1, "size": 12.3}}} 

+

83 >>> flatten(nested) 

+

84 {('tumor', '1', 't_stage'): 1, ('tumor', '1', 'size'): 12.3} 

+

85 >>> mapping = {"patient": {"#": {"age": {"func": int, "columns": ["age"]}}}} 

+

86 >>> flatten(mapping, max_depth=3) 

+

87 {('patient', '#', 'age'): {'func': <class 'int'>, 'columns': ['age']}} 

+

88 

+

89 Note that flattening an already flat dictionary will yield some weird results. 

+

90 """ 

+

91 result = {} 

+

92 

+

93 for key, value in nested.items(): 

+

94 is_dict = isinstance(value, dict) 

+

95 has_reached_max_depth = max_depth is not None and len(prev_key) >= max_depth - 1 

+

96 

+

97 if is_dict and not has_reached_max_depth: 

+

98 result.update(flatten(value, (*prev_key, key), max_depth)) 

+

99 else: 

+

100 result[(*prev_key, key)] = value 

+

101 

+

102 return result 

+

103 

+

104 

+

105def unflatten(flat: dict) -> dict: 

+

106 """Take a flat dictionary with tuples of keys and create nested dict from it. 

+

107 

+

108 >>> flat = {('tumor', '1', 't_stage'): 1, ('tumor', '1', 'size'): 12.3} 

+

109 >>> unflatten(flat) 

+

110 {'tumor': {'1': {'t_stage': 1, 'size': 12.3}}} 

+

111 >>> mapping = {('patient', '#', 'age'): {'func': int, 'columns': ['age']}} 

+

112 >>> unflatten(mapping) 

+

113 {'patient': {'#': {'age': {'func': <class 'int'>, 'columns': ['age']}}}} 

+

114 """ 

+

115 result = {} 

+

116 

+

117 for keys, value in flat.items(): 

+

118 current = result 

+

119 for key in keys[:-1]: 

+

120 current = current.setdefault(key, {}) 

+

121 

+

122 current[keys[-1]] = value 

+

123 

+

124 return result 

+

125 

+

126 

+

127def get_modalities_subset( 

+

128 defined_modalities: dict[str, list[float]], 

+

129 selection: list[str], 

+

130) -> dict[str, list[float]]: 

+

131 """Of the ``defined_modalities`` return only those mentioned in the ``selection``. 

+

132 

+

133 >>> modalities = {"CT": [0.76, 0.81], "MRI": [0.63, 0.86]} 

+

134 >>> get_modalities_subset(modalities, ["CT"]) 

+

135 {'CT': [0.76, 0.81]} 

+

136 """ 

+

137 selected_modalities = {} 

+

138 for mod in selection: 

+

139 try: 

+

140 selected_modalities[mod] = defined_modalities[mod] 

+

141 except KeyError as key_err: 

+

142 raise KeyError(f"Modality {mod} has not been defined yet") from key_err 

+

143 return selected_modalities 

+

144 

+

145 

+

146def load_patient_data( 

+

147 file_path: Path, 

+

148 **read_csv_kwargs: dict, 

+

149) -> pd.DataFrame: 

+

150 """Load patient data from a CSV file stored at ``file``.""" 

+

151 if "header" not in read_csv_kwargs: 

+

152 read_csv_kwargs["header"] = [0, 1, 2] 

+

153 

+

154 data = pd.read_csv(file_path, **read_csv_kwargs) 

+

155 logger.info(f"Loaded {len(data)} patient records from {file_path}") 

+

156 return data 

+

157 

+

158 

+

159@check_input_file_exists 

+

160def load_yaml_params(file_path: Path) -> dict: 

+

161 """Load parameters from a YAML ``file``.""" 

+

162 with open(file_path, encoding="utf-8") as file: 

+

163 loaded_params = yaml.safe_load(file) 

+

164 logger.info(f"Loaded YAML parameters from {file_path}") 

+

165 return loaded_params 

+

166 

+

167 

+

168@check_input_file_exists 

+

169def load_model_samples( 

+

170 file_path: Path, 

+

171 name: str = "mcmc", 

+

172 flat: bool = True, 

+

173 discard: int = 0, 

+

174 thin: int = 1, 

+

175) -> np.ndarray: 

+

176 """Load MCMC samples stored in HDF5 file at ``file_path`` under a key ``name``.""" 

+

177 backend = HDFBackend(file_path, name=name, read_only=True) 

+

178 samples = backend.get_chain(flat=flat, discard=discard, thin=thin) 

+

179 logger.info(f"Loaded samples with shape {samples.shape} from {file_path}") 

+

180 return samples 

+

181 

+

182 

+

183@check_output_dir_exists 

+

184def get_hdf5_backend( 

+

185 file_path: Path, 

+

186 dataset: str = "mcmc", 

+

187 nwalkers: int | None = None, 

+

188 ndim: int | None = None, 

+

189 reset: bool = False, 

+

190) -> HDFBackend: 

+

191 """Open an HDF5 file at ``file_path`` and return a backend.""" 

+

192 backend = HDFBackend(file_path, name=dataset) 

+

193 logger.info(f"Opened HDF5 file at {file_path}") 

+

194 

+

195 if reset: 

+

196 logger.info(f"Resetting backend at {file_path} to {nwalkers=} and {ndim=}") 

+

197 backend.reset(nwalkers, ndim) 

+

198 

+

199 return backend 

+
+ + + diff --git a/htmlcov/z_9b7bcb970ba14d6a___init___py.html b/htmlcov/z_9b7bcb970ba14d6a___init___py.html new file mode 100644 index 0000000..a2eebe1 --- /dev/null +++ b/htmlcov/z_9b7bcb970ba14d6a___init___py.html @@ -0,0 +1,140 @@ + + + + + Coverage for src/lyscripts/data/__init__.py: 92% + + + + + +
+
+

+ Coverage for src/lyscripts/data/__init__.py: + 92% +

+ +

+ 12 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Commands and functions for managing CSV data on patterns of lymphatic progression. 

+

2 

+

3This contains helpful CLI commands that allow building quick and reproducible workflows 

+

4even when using language-agnostic tools like `Make`_ or `DVC`_. 

+

5 

+

6Most of these commands can load `LyProX`_ style data from CSV files, but also from 

+

7the installed datasets provided by the `lydata`_ package and directly from the 

+

8associated `GitHub repository`_. 

+

9 

+

10.. _Make: https://www.gnu.org/software/make/ 

+

11.. _DVC: https://dvc.org 

+

12.. _LyProX: https://lyprox.org 

+

13.. _lydata: https://lydata.readthedocs.io 

+

14.. _GitHub repository: https://github.com/rmnldwg/lydata 

+

15""" 

+

16 

+

17from pydantic_settings import BaseSettings, CliApp, CliSubCommand 

+

18 

+

19from lyscripts.data import ( # noqa: F401 

+

20 enhance, 

+

21 generate, 

+

22 join, 

+

23 lyproxify, 

+

24 split, 

+

25) 

+

26 

+

27# Avoid conflict with built-in `filter` function 

+

28from lyscripts.data import filter as filter_ 

+

29 

+

30 

+

31class DataCLI(BaseSettings): 

+

32 """Work with lymphatic progression data through this CLI.""" 

+

33 

+

34 lyproxify: CliSubCommand[lyproxify.LyproxifyCLI] 

+

35 join: CliSubCommand[join.JoinCLI] 

+

36 split: CliSubCommand[split.SplitCLI] 

+

37 filter: CliSubCommand[filter_.FilterCLI] 

+

38 enhance: CliSubCommand[enhance.EnhanceCLI] 

+

39 generate: CliSubCommand[generate.GenerateCLI] 

+

40 

+

41 def cli_cmd(self) -> None: 

+

42 """Run one of the ``data`` subcommands.""" 

+

43 CliApp.run_subcommand(self) 

+
+ + + diff --git a/htmlcov/z_9b7bcb970ba14d6a___main___py.html b/htmlcov/z_9b7bcb970ba14d6a___main___py.html new file mode 100644 index 0000000..968898f --- /dev/null +++ b/htmlcov/z_9b7bcb970ba14d6a___main___py.html @@ -0,0 +1,133 @@ + + + + + Coverage for src/lyscripts/data/__main__.py: 0% + + + + + +
+
+

+ Coverage for src/lyscripts/data/__main__.py: + 0% +

+ +

+ 18 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Run the data module as a script.""" 

+

2 

+

3import argparse 

+

4 

+

5from lyscripts import exit_cli 

+

6from lyscripts.cli import RichDefaultHelpFormatter 

+

7from lyscripts.data import enhance, generate, join, split 

+

8 

+

9# Avoid conflict with built-in `filter` function 

+

10from lyscripts.data import filter as filter_ 

+

11 

+

12 

+

13def main(args: argparse.Namespace): 

+

14 """Run the main script.""" 

+

15 parser = argparse.ArgumentParser( 

+

16 prog="lyscripts data", 

+

17 description=__doc__, 

+

18 formatter_class=RichDefaultHelpFormatter, 

+

19 ) 

+

20 parser.set_defaults(run_main=exit_cli) 

+

21 subparsers = parser.add_subparsers() 

+

22 

+

23 # the individual scripts add `ArgumentParser` instances and their arguments to 

+

24 # this `subparsers` object 

+

25 enhance._add_parser(subparsers, help_formatter=parser.formatter_class) 

+

26 generate._add_parser(subparsers, help_formatter=parser.formatter_class) 

+

27 join._add_parser(subparsers, help_formatter=parser.formatter_class) 

+

28 split._add_parser(subparsers, help_formatter=parser.formatter_class) 

+

29 filter_._add_parser(subparsers, help_formatter=parser.formatter_class) 

+

30 

+

31 args = parser.parse_args() 

+

32 args.run_main(args, parser) 

+

33 

+

34 

+

35if __name__ == "__main__": 

+

36 main() 

+
+ + + diff --git a/htmlcov/z_9b7bcb970ba14d6a_enhance_py.html b/htmlcov/z_9b7bcb970ba14d6a_enhance_py.html new file mode 100644 index 0000000..2f99823 --- /dev/null +++ b/htmlcov/z_9b7bcb970ba14d6a_enhance_py.html @@ -0,0 +1,160 @@ + + + + + Coverage for src/lyscripts/data/enhance.py: 67% + + + + + +
+
+

+ Coverage for src/lyscripts/data/enhance.py: + 67% +

+ +

+ 24 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Enhance the dataset by inferring additional columns from the data. 

+

2 

+

3This is a command-line interface to the 

+

4:py:func:`~lydata.utils.infer_and_combine_levels` function. 

+

5""" 

+

6 

+

7from typing import Literal 

+

8 

+

9from loguru import logger 

+

10from lydata import infer_and_combine_levels 

+

11from lydata.utils import ModalityConfig 

+

12 

+

13from lyscripts.cli import assemble_main 

+

14from lyscripts.configs import BaseCLI, DataConfig 

+

15from lyscripts.data.utils import save_table_to_csv 

+

16 

+

17 

+

18class EnhanceCLI(BaseCLI): 

+

19 """Enhance the dataset by inferring additional columns from the data.""" 

+

20 

+

21 input: DataConfig 

+

22 modalities: dict[str, ModalityConfig] | None = None 

+

23 method: Literal["max_llh", "rank"] = "max_llh" 

+

24 sides: list[Literal["ipsi", "contra"]] = ["ipsi", "contra"] 

+

25 lnl_subdivisions: dict[str, list[str]] = { 

+

26 "I": ["a", "b"], 

+

27 "II": ["a", "b"], 

+

28 "V": ["a", "b"], 

+

29 } 

+

30 output_file: str 

+

31 

+

32 def cli_cmd(self) -> None: 

+

33 """Infer additional columns from the data and save the enhanced dataset. 

+

34 

+

35 This basically provides a CLI to the 

+

36 :py:func:`~lydata.utils.infer_and_combine_levels` function. See its docs for 

+

37 more details on what exactly is happening here. 

+

38 """ 

+

39 logger.debug(self.model_dump_json(indent=2)) 

+

40 

+

41 data = self.input.load() 

+

42 modality_names = list(self.modalities.keys()) if self.modalities else None 

+

43 

+

44 infer_lvls_kwargs = { 

+

45 "modalities": modality_names, 

+

46 "sides": self.sides, 

+

47 "subdivisions": self.lnl_subdivisions, 

+

48 } 

+

49 enhanced = infer_and_combine_levels( 

+

50 dataset=data, 

+

51 infer_superlevels_kwargs=infer_lvls_kwargs, 

+

52 infer_sublevels_kwargs=infer_lvls_kwargs, 

+

53 combine_kwargs={ 

+

54 "modalities": self.modalities, 

+

55 "method": self.method, 

+

56 }, 

+

57 ) 

+

58 save_table_to_csv(file_path=self.output_file, table=enhanced) 

+

59 

+

60 

+

61if __name__ == "__main__": 

+

62 main = assemble_main(settings_cls=EnhanceCLI, prog_name="enhance") 

+

63 main() 

+
+ + + diff --git a/htmlcov/z_9b7bcb970ba14d6a_filter_py.html b/htmlcov/z_9b7bcb970ba14d6a_filter_py.html new file mode 100644 index 0000000..b6da490 --- /dev/null +++ b/htmlcov/z_9b7bcb970ba14d6a_filter_py.html @@ -0,0 +1,196 @@ + + + + + Coverage for src/lyscripts/data/filter.py: 39% + + + + + +
+
+

+ Coverage for src/lyscripts/data/filter.py: + 39% +

+ +

+ 49 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Filter a dataset according to some common criteria. 

+

2 

+

3This is essentially a command line interface to building a 

+

4:py:class:`query object <lydata.accessor.Q>` and applying it to the dataset. 

+

5""" 

+

6 

+

7from pathlib import Path 

+

8from typing import Literal 

+

9 

+

10from loguru import logger 

+

11from lydata import Q 

+

12from pydantic import Field 

+

13from pydantic_settings import CliImplicitFlag 

+

14 

+

15from lyscripts.cli import assemble_main 

+

16from lyscripts.configs import BaseCLI, DataConfig 

+

17from lyscripts.data.utils import save_table_to_csv 

+

18 

+

19 

+

20class FilterCLI(BaseCLI): 

+

21 """In- or exclude patients where a certain column fulfills a certain condition.""" 

+

22 

+

23 input: DataConfig 

+

24 include: CliImplicitFlag[bool] = Field( 

+

25 False, 

+

26 description="Include patients where the condition is met (default: exclude).", 

+

27 ) 

+

28 column: list[str] | str = Field( 

+

29 description=( 

+

30 "The column to filter by. May be a tuple of three strings, since data " 

+

31 "has a three-level header. If it is only one string, the lydata package " 

+

32 "tries to map that to a three-level header." 

+

33 ), 

+

34 ) 

+

35 operator: Literal["==", "!=", ">", "<", ">=", "<=", "in", "contains"] = Field( 

+

36 description="The operator to use for comparison.", 

+

37 ) 

+

38 value: float | int | str = Field(description="The value to compare against.") 

+

39 output_file: Path = Field(description="The path to save the filtered dataset to.") 

+

40 

+

41 def model_post_init(self, __context): 

+

42 """Cast to ``float``, if not possible ``int``, if not possible ``str``.""" 

+

43 if isinstance(self.column, list): 

+

44 if len(self.column) == 1: 

+

45 self.column = self.column[0] 

+

46 elif len(self.column) == 3: 

+

47 self.column = tuple(self.column) 

+

48 else: 

+

49 raise ValueError( 

+

50 "The column attribute must be an iterable of three strings or a " 

+

51 f"single string, but it is {self.column}.", 

+

52 ) 

+

53 

+

54 try: 

+

55 self.value = float(self.value) 

+

56 return super().model_post_init(__context) 

+

57 except ValueError: 

+

58 pass 

+

59 

+

60 try: 

+

61 self.value = int(self.value) 

+

62 return super().model_post_init(__context) 

+

63 except ValueError: 

+

64 pass 

+

65 

+

66 return super().model_post_init(__context) 

+

67 

+

68 def cli_cmd(self): 

+

69 """Execute the ``filter`` command. 

+

70 

+

71 This command uses the :py:class:`~lydata.accessor.Q` objects of the `lydata`_ 

+

72 library to filter the dataset according to the given criteria. 

+

73 

+

74 .. _lydata: https://lydata.readthedocs.io 

+

75 """ 

+

76 logger.debug(self.model_dump_json(indent=2)) 

+

77 

+

78 data = self.input.load() 

+

79 query = Q( 

+

80 column=self.column, 

+

81 operator=self.operator, 

+

82 value=self.value, 

+

83 ) 

+

84 logger.debug(f"Created query object: {query}") 

+

85 mask = query.execute(data) 

+

86 

+

87 if self.include: 

+

88 filtered = data[mask] 

+

89 logger.info(f"Keeping {sum(mask)} of {len(data)} patients.") 

+

90 else: 

+

91 filtered = data[~mask] 

+

92 logger.info(f"Excluding {sum(mask)} of {len(data)} patients.") 

+

93 

+

94 save_table_to_csv(file_path=self.output_file, table=filtered) 

+

95 

+

96 

+

97if __name__ == "__main__": 

+

98 main = assemble_main(settings_cls=FilterCLI, prog_name="filter") 

+

99 main() 

+
+ + + diff --git a/htmlcov/z_9b7bcb970ba14d6a_generate_py.html b/htmlcov/z_9b7bcb970ba14d6a_generate_py.html new file mode 100644 index 0000000..6d3d59b --- /dev/null +++ b/htmlcov/z_9b7bcb970ba14d6a_generate_py.html @@ -0,0 +1,193 @@ + + + + + Coverage for src/lyscripts/data/generate.py: 90% + + + + + +
+
+

+ Coverage for src/lyscripts/data/generate.py: + 90% +

+ +

+ 39 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Script to generate a synthetic dataset. 

+

2 

+

3The generation is done by the :py:meth:`~lymph.models.Unilateral.draw_patients` method 

+

4of 

+

5the `lymph`_ package, which is why this requires the specification of a model 

+

6via the :py:class:`~lyscripts.configs.ModelConfig` class. 

+

7 

+

8.. _lymph: https://lymph-model.readthedocs.io/ 

+

9""" 

+

10 

+

11import numpy as np 

+

12from loguru import logger 

+

13from lydata.utils import ModalityConfig 

+

14from pydantic import Field 

+

15 

+

16from lyscripts.cli import assemble_main 

+

17from lyscripts.configs import ( 

+

18 BaseCLI, 

+

19 DistributionConfig, 

+

20 GraphConfig, 

+

21 ModelConfig, 

+

22 add_distributions, 

+

23 add_modalities, 

+

24 construct_model, 

+

25) 

+

26from lyscripts.data.utils import save_table_to_csv 

+

27 

+

28 

+

29class GenerateCLI(BaseCLI): 

+

30 """Settings for the command-line interface.""" 

+

31 

+

32 graph: GraphConfig 

+

33 model: ModelConfig = ModelConfig() 

+

34 distributions: dict[str, DistributionConfig] = Field( 

+

35 default={}, 

+

36 description=( 

+

37 "Mapping of model T-categories to predefined distributions over " 

+

38 "diagnose times." 

+

39 ), 

+

40 ) 

+

41 t_stages_dist: dict[str, float] = Field( 

+

42 description=( 

+

43 "Specify what fraction of generated patients should come from the " 

+

44 "respective T-Stage." 

+

45 ), 

+

46 ) 

+

47 modalities: dict[str, ModalityConfig] 

+

48 params: dict[str, float] 

+

49 num_patients: int = 200 

+

50 output_file: str 

+

51 seed: int = 42 

+

52 

+

53 def model_post_init(self, __context) -> None: 

+

54 """Make sure distribution over T-stages is normalized.""" 

+

55 total = 0.0 

+

56 for t_stage in self.distributions: 

+

57 if t_stage not in self.t_stages_dist: 

+

58 raise ValueError(f"Missing distribution for T-stage {t_stage}.") 

+

59 

+

60 total += self.t_stages_dist[t_stage] 

+

61 

+

62 if not np.isclose(total, 1.0): 

+

63 raise ValueError("Sum of T-stage distributions must be 1.") 

+

64 

+

65 return super().model_post_init(__context) 

+

66 

+

67 def cli_cmd(self) -> None: 

+

68 """Run the ``generate`` command. 

+

69 

+

70 Here, the command constructs a model from the settings provided via the 

+

71 arguments. It then generates a synthetic dataset using the 

+

72 :py:meth:`~lymph.models.Unilateral.draw_patients` from the `lymph`_ package. 

+

73 

+

74 .. _lymph: https://lymph-model.readthedocs.io/ 

+

75 """ 

+

76 logger.debug(self.model_dump_json(indent=2)) 

+

77 

+

78 model = construct_model(self.model, self.graph) 

+

79 model = add_distributions(model, self.distributions) 

+

80 model = add_modalities(model, self.modalities) 

+

81 model.set_params(**self.params) 

+

82 logger.info(f"Set parameters: {model.get_params(as_dict=True)}") 

+

83 

+

84 synth_data = model.draw_patients( 

+

85 num=self.num_patients, 

+

86 stage_dist=list(self.t_stages_dist.values()), 

+

87 seed=self.seed, 

+

88 ) 

+

89 logger.info(f"Generated synthetic data with shape {synth_data.shape}") 

+

90 

+

91 save_table_to_csv(file_path=self.output_file, table=synth_data) 

+

92 

+

93 

+

94if __name__ == "__main__": 

+

95 main = assemble_main(settings_cls=GenerateCLI, prog_name="data generate") 

+

96 main() 

+
+ + + diff --git a/htmlcov/z_9b7bcb970ba14d6a_join_py.html b/htmlcov/z_9b7bcb970ba14d6a_join_py.html new file mode 100644 index 0000000..61609b3 --- /dev/null +++ b/htmlcov/z_9b7bcb970ba14d6a_join_py.html @@ -0,0 +1,174 @@ + + + + + Coverage for src/lyscripts/data/join.py: 55% + + + + + +
+
+

+ Coverage for src/lyscripts/data/join.py: + 55% +

+ +

+ 20 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Join multiple lymphatic progression datasets into a single dataset.""" 

+

2 

+

3from pathlib import Path 

+

4 

+

5import pandas as pd 

+

6from pydantic import Field 

+

7 

+

8from lyscripts.cli import assemble_main 

+

9from lyscripts.configs import BaseCLI, DataConfig 

+

10from lyscripts.data.utils import save_table_to_csv 

+

11 

+

12 

+

13class JoinCLI(BaseCLI): 

+

14 """Join multiple lymphatic progression datasets into a single dataset.""" 

+

15 

+

16 inputs: list[DataConfig] = Field(description="The datasets to join.") 

+

17 output_file: Path = Field(description="The path to the output dataset.") 

+

18 

+

19 def cli_cmd(self) -> None: 

+

20 r"""Start the ``join`` subcommand. 

+

21 

+

22 This will load all datasets specified in the ``inputs`` attribute and 

+

23 concatenate them into a single dataset. 

+

24 

+

25 Unfortunately, the use of `pydantic`_ does make this particular command a 

+

26 little bit more complicated (but also more powerful): If one simply wants to 

+

27 concatenate multiple datasets on disk, the ``inputs`` should be provided like 

+

28 this: 

+

29 

+

30 .. code-block:: bash 

+

31 

+

32 lydata join \ 

+

33 --inputs='["data.source": "file1.csv", "data.source": "file2.csv"]' \ 

+

34 --output="joined.csv" 

+

35 

+

36 But it also allows for concatenating datasets fetched directly from the 

+

37 `lydata Github repo`_. Due to the rather complex command signature, we 

+

38 recommend defining what to concatenate using a YAML file: 

+

39 

+

40 .. code-block:: yaml 

+

41 

+

42 inputs: 

+

43 - data.year: 2021 

+

44 data.institution: "usz" 

+

45 data.subsite: "oropharynx" 

+

46 - data.year: 2021 

+

47 data.institution: "clb" 

+

48 data.subsite: "oropharynx" 

+

49 

+

50 Then, the command will look like this: 

+

51 

+

52 .. code-block:: bash 

+

53 

+

54 lydata join --configs=datasets.ly.yaml --output=joined.csv 

+

55 

+

56 .. _pydantic: https://docs.pydantic.dev/latest/ 

+

57 .. _lydata Github repo: https://github.com/rmnldwg/lydata 

+

58 """ 

+

59 joined = None 

+

60 

+

61 for data_config in self.inputs: 

+

62 data = data_config.load() 

+

63 if joined is None: 

+

64 joined = data 

+

65 else: 

+

66 joined = pd.concat( 

+

67 [joined, data], 

+

68 axis="index", 

+

69 ignore_index=True, 

+

70 ) 

+

71 

+

72 save_table_to_csv(file_path=self.output_file, table=joined) 

+

73 

+

74 

+

75if __name__ == "__main__": 

+

76 main = assemble_main(settings_cls=JoinCLI, prog_name="join") 

+

77 main() 

+
+ + + diff --git a/htmlcov/z_9b7bcb970ba14d6a_lyproxify_py.html b/htmlcov/z_9b7bcb970ba14d6a_lyproxify_py.html new file mode 100644 index 0000000..8f5078d --- /dev/null +++ b/htmlcov/z_9b7bcb970ba14d6a_lyproxify_py.html @@ -0,0 +1,436 @@ + + + + + Coverage for src/lyscripts/data/lyproxify.py: 45% + + + + + +
+
+

+ Coverage for src/lyscripts/data/lyproxify.py: + 45% +

+ +

+ 121 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Consumes raw data and transforms it into a CSV that `LyProX`_ understands. 

+

2 

+

3To do so, it needs a dictionary that defines a mapping from raw columns to the LyProX 

+

4style data format. See the documentation of the :py:func:`.transform_to_lyprox` function 

+

5for more information. 

+

6 

+

7.. _LyProX: https://lyprox.org 

+

8""" 

+

9 

+

10import importlib.util 

+

11import warnings 

+

12from pathlib import Path 

+

13from typing import Annotated, Any 

+

14 

+

15import pandas as pd 

+

16from loguru import logger 

+

17from pydantic import AfterValidator, Field, FilePath 

+

18 

+

19from lyscripts.cli import assemble_main 

+

20from lyscripts.configs import BaseCLI 

+

21from lyscripts.data.utils import save_table_to_csv 

+

22from lyscripts.utils import delete_private_keys, flatten, load_patient_data 

+

23 

+

24warnings.simplefilter(action="ignore", category=FutureWarning) 

+

25 

+

26 

+

27def ensure_python_file(file: Path) -> Path: 

+

28 """Check if the file is a Python file.""" 

+

29 if file.suffix != ".py": 

+

30 raise ValueError("Mapping file must be a Python file.") 

+

31 

+

32 return file 

+

33 

+

34 

+

35def ensure_column_map(file: Path) -> Path: 

+

36 """Ensure the Python file contains a ``COLUMN_MAP`` dictionary.""" 

+

37 spec = importlib.util.spec_from_file_location("map_module", file) 

+

38 mapping = importlib.util.module_from_spec(spec) 

+

39 spec.loader.exec_module(mapping) 

+

40 

+

41 if not hasattr(mapping, "COLUMN_MAP"): 

+

42 raise ValueError("Mapping file must contain a `COLUMN_MAP` dictionary.") 

+

43 

+

44 return file 

+

45 

+

46 

+

47class LyproxifyCLI(BaseCLI): 

+

48 """Map any CSV file to the LyProX format with the help of a Python mapping dict.""" 

+

49 

+

50 input_file: FilePath = Field(description="Location of raw CSV data.") 

+

51 num_header_rows: int = Field( 

+

52 default=1, 

+

53 description="Number of rows comprising the header of the raw CSV file.", 

+

54 ) 

+

55 mapping_file: Annotated[ 

+

56 FilePath, 

+

57 AfterValidator(ensure_python_file), 

+

58 AfterValidator(ensure_column_map), 

+

59 ] = Field( 

+

60 description=( 

+

61 "Location of Python file containing a `COLUMN_MAP` dictionary. It may also " 

+

62 "contain an `EXCLUDE` list of tuples `(column, check)` to exclude patients." 

+

63 ), 

+

64 ) 

+

65 drop_rows: list[int] = Field( 

+

66 default=[], 

+

67 description=( 

+

68 "Delete rows of specified indices. Counting of rows start at 0 _after_ " 

+

69 "the `header-rows`." 

+

70 ), 

+

71 ) 

+

72 drop_cols: list[int] = Field( 

+

73 default=[], 

+

74 description="Delete columns of specified indices.", 

+

75 ) 

+

76 output_file: Path = Field(description="Location to store the lyproxified CSV file.") 

+

77 

+

78 def cli_cmd(self) -> None: 

+

79 """Start the ``lyproxify`` subcommand. 

+

80 

+

81 After reading in the specified file, it will first ``drop_rows`` and 

+

82 ``drop_cols``, as specified in the command line arguments. Then, it will 

+

83 call :py:func:`.exclude_patients` which will further remove patients based 

+

84 on the ``EXCLUDE`` object in the ``mapping_file``. Finally, it will call 

+

85 :py:func:`.transform_to_lyprox` to transform the data into the LyProX format 

+

86 given the ``COLUMN_MAP`` object in the ``mapping_file``. 

+

87 """ 

+

88 logger.debug(self.model_dump_json(indent=2)) 

+

89 

+

90 raw = load_patient_data( 

+

91 file_path=self.input_file, 

+

92 header=list(range(self.num_header_rows)), 

+

93 ) 

+

94 raw = clean_header( 

+

95 table=raw, 

+

96 num_cols=raw.shape[1], 

+

97 num_header_rows=self.num_header_rows, 

+

98 ) 

+

99 

+

100 cols_to_drop = raw.columns[self.drop_cols] 

+

101 trimmed = raw.drop(cols_to_drop, axis="columns") 

+

102 trimmed = trimmed.drop(index=self.drop_rows) 

+

103 trimmed = trimmed.dropna(axis="index", how="all") 

+

104 logger.info(f"Dropped rows {self.drop_rows} and columns {cols_to_drop}.") 

+

105 

+

106 spec = importlib.util.spec_from_file_location("map_module", self.mapping_file) 

+

107 mapping = importlib.util.module_from_spec(spec) 

+

108 spec.loader.exec_module(mapping) 

+

109 logger.info(f"Imported mapping instructions from {self.mapping_file}") 

+

110 

+

111 reduced = exclude_patients(trimmed, mapping.EXCLUDE) 

+

112 processed = transform_to_lyprox(reduced, mapping.COLUMN_MAP) 

+

113 

+

114 if ("tumor", "1", "side") in processed.columns: 

+

115 processed = leftright_to_ipsicontra(processed) 

+

116 

+

117 save_table_to_csv(file_path=self.output_file, table=processed) 

+

118 

+

119 

+

120class ParsingError(Exception): 

+

121 """Error while parsing the CSV file.""" 

+

122 

+

123 

+

124def clean_header( 

+

125 table: pd.DataFrame, 

+

126 num_cols: int, 

+

127 num_header_rows: int, 

+

128) -> pd.DataFrame: 

+

129 """Rename the header cells in the ``table``.""" 

+

130 table = table.copy() 

+

131 

+

132 for col in range(num_cols): 

+

133 for row in range(num_header_rows): 

+

134 table.rename( 

+

135 columns={f"Unnamed: {col}_level_{row}": f"{col}_lvl_{row}"}, 

+

136 inplace=True, 

+

137 ) 

+

138 

+

139 logger.debug("Cleaned headers of the raw data.") 

+

140 return table 

+

141 

+

142 

+

143def get_instruction_depth(nested_column_map: dict[tuple, dict[str, Any]]) -> int: 

+

144 """Get the depth at which the column mapping instructions are nested. 

+

145 

+

146 Instructions are a dictionary that contains either a 'func' or 'default' key. 

+

147 

+

148 >>> nested_column_map = {"patient": {"age": {"func": int}}} 

+

149 >>> get_instruction_depth(nested_column_map) 

+

150 2 

+

151 >>> flat_column_map = flatten(nested_column_map, max_depth=2) 

+

152 >>> get_instruction_depth(flat_column_map) 

+

153 1 

+

154 >>> nested_column_map = {"patient": {"__doc__": "some patient info", "age": 61}} 

+

155 >>> get_instruction_depth(nested_column_map) 

+

156 Traceback (most recent call last): 

+

157 ... 

+

158 ValueError: Leaf of column map must be a dictionary with 'func' or 'default' key. 

+

159 """ 

+

160 for _, value in nested_column_map.items(): 

+

161 if isinstance(value, dict): 

+

162 if "func" in value or "default" in value: 

+

163 return 1 

+

164 

+

165 return 1 + get_instruction_depth(value) 

+

166 

+

167 raise ValueError( 

+

168 "Leaf of column map must be a dictionary with 'func' or 'default' key.", 

+

169 ) 

+

170 

+

171 raise ValueError("Empty column map.") 

+

172 

+

173 

+

174def generate_markdown_docs( 

+

175 nested_column_map: dict[tuple, dict[str, Any]], 

+

176 depth: int = 0, 

+

177 indent_len: int = 4, 

+

178) -> str: 

+

179 r"""Generate a markdown nested, ordered list as documentation for the column map. 

+

180 

+

181 A key in the doctionary is supposed to be documented, when its value is a dictionary 

+

182 containing a ``"__doc__"`` key. 

+

183 

+

184 >>> nested_column_map = { 

+

185 ... "patient": { 

+

186 ... "__doc__": "some patient info", 

+

187 ... "age": { 

+

188 ... "__doc__": "age of the patient", 

+

189 ... "func": int, 

+

190 ... "columns": ["age"], 

+

191 ... }, 

+

192 ... }, 

+

193 ... } 

+

194 >>> generate_markdown_docs(nested_column_map) 

+

195 '1. **`patient:`** some patient info\n 1. **`age:`** age of the patient\n' 

+

196 """ 

+

197 md_docs = "" 

+

198 indent = " " * indent_len * depth 

+

199 i = 1 

+

200 for key, value in nested_column_map.items(): 

+

201 if isinstance(value, dict): 

+

202 if "__doc__" in value: 

+

203 md_docs += f"{indent}{i}. **`{key}:`** {value['__doc__']}\n" 

+

204 i += 1 

+

205 

+

206 md_docs += generate_markdown_docs(value, depth + 1, indent_len) 

+

207 

+

208 return md_docs 

+

209 

+

210 

+

211def transform_to_lyprox( 

+

212 raw: pd.DataFrame, 

+

213 column_map: dict[tuple, dict[str, Any]], 

+

214) -> pd.DataFrame: 

+

215 """Transform ``raw`` data into table that can be uploaded directly to `LyProX`_. 

+

216 

+

217 To do so, it uses instructions in the `colum_map` dictionary, that needs to have 

+

218 a particular structure: 

+

219 

+

220 For each column in the final 'lyproxified' `pd.DataFrame`, one entry must exist in 

+

221 the `column_map` dictionary. E.g., for the column corresponding to a patient's age, 

+

222 the dictionary should contain a key-value pair of this shape: 

+

223 

+

224 .. code-block:: python 

+

225 

+

226 column_map = { 

+

227 ("patient", "#", "age"): { 

+

228 "func": compute_age_from_raw, 

+

229 "kwargs": {"randomize": False}, 

+

230 "columns": ["birthday", "date of diagnosis"] 

+

231 }, 

+

232 } 

+

233 

+

234 In this example, the function ``compute_age_from_raw`` is called with the 

+

235 values of the columns ``"birthday"`` and ``"date of diagnosis"`` as positional 

+

236 arguments, and the keyword argument ``"randomize"`` is set to ``False``. The 

+

237 function then returns the patient's age, which is subsequently stored in the column 

+

238 ``("patient", "#", "age")``. 

+

239 

+

240 Note that the ``column_map`` dictionary must have either a ``"default"`` key or 

+

241 ``"func"`` along with ``"columns"`` and ``"kwargs"``, depending on the function 

+

242 definition. If the function does not take any arguments, ``"columns"`` can be 

+

243 omitted. If it also does not take any keyword arguments, ``"kwargs"`` can be 

+

244 omitted, too. 

+

245 

+

246 .. _LyProX: https://lyprox.org 

+

247 """ 

+

248 column_map = delete_private_keys(column_map) 

+

249 

+

250 if (instruction_depth := get_instruction_depth(column_map)) > 1: 

+

251 column_map = flatten(column_map, max_depth=instruction_depth) 

+

252 

+

253 multi_idx = pd.MultiIndex.from_tuples(column_map.keys()) 

+

254 processed = pd.DataFrame(columns=multi_idx) 

+

255 

+

256 for multi_idx_col, instruction in column_map.items(): 

+

257 if instruction != "": 

+

258 if "default" in instruction: 

+

259 processed[multi_idx_col] = [instruction["default"]] * len(raw) 

+

260 elif "func" in instruction: 

+

261 cols = instruction.get("columns", []) 

+

262 kwargs = instruction.get("kwargs", {}) 

+

263 func = instruction["func"] 

+

264 

+

265 try: 

+

266 processed[multi_idx_col] = [ 

+

267 func(*vals, **kwargs) for vals in raw[cols].values 

+

268 ] 

+

269 except Exception as exc: 

+

270 raise ParsingError( 

+

271 f"Exception encountered while parsing column {multi_idx_col}", 

+

272 ) from exc 

+

273 else: 

+

274 raise ParsingError( 

+

275 f"Column {multi_idx_col} has neither a `default` value nor `func` " 

+

276 "describing how to fill this column.", 

+

277 ) 

+

278 

+

279 logger.info("Transformed raw data to LyProX format.") 

+

280 return processed 

+

281 

+

282 

+

283def leftright_to_ipsicontra(data: pd.DataFrame): 

+

284 """Change absolute side reporting to tumor-relative. 

+

285 

+

286 Transform reporting of LNL involvement by absolute side (right & left) to a 

+

287 reporting relative to the tumor (ipsi- & contralateral). The table ``data`` should 

+

288 already be in the format LyProX requires, except for the side-reporting of LNL 

+

289 involvement. 

+

290 """ 

+

291 len_before = len(data) 

+

292 left_data = data.loc[data["tumor", "1", "side"] != "right"] 

+

293 right_data = data.loc[data["tumor", "1", "side"] == "right"] 

+

294 

+

295 left_data = left_data.rename(columns={"left": "ipsi"}, level=1) 

+

296 left_data = left_data.rename(columns={"right": "contra"}, level=1) 

+

297 right_data = right_data.rename(columns={"left": "contra"}, level=1) 

+

298 right_data = right_data.rename(columns={"right": "ipsi"}, level=1) 

+

299 

+

300 data = pd.concat([left_data, right_data], ignore_index=True) 

+

301 if len_before != len(data): 

+

302 raise RuntimeError("Number of patients changed") 

+

303 

+

304 logger.info("Transformed side reporting to ipsi- and contralateral.") 

+

305 return data 

+

306 

+

307 

+

308def exclude_patients(raw: pd.DataFrame, exclude: list[tuple[str, Any]]): 

+

309 """Exclude patients in the ``raw`` data based on a list of what to ``exclude``. 

+

310 

+

311 The ``exclude`` list contains tuples ``(column, check)``. The ``check`` function 

+

312 will then exclude any patients from the cohort where ``check(raw[column])`` 

+

313 evaluates to ``True``. 

+

314 

+

315 >>> exclude = [("age", lambda s: s > 50)] 

+

316 >>> table = pd.DataFrame({ 

+

317 ... "age": [43, 82, 18, 67], 

+

318 ... "T-category": [ 3, 4, 2, 1], 

+

319 ... }) 

+

320 >>> exclude_patients(table, exclude) 

+

321 age T-category 

+

322 0 43 3 

+

323 2 18 2 

+

324 """ 

+

325 num_before = len(raw) 

+

326 filtered = raw.copy() 

+

327 

+

328 for column, check in exclude: 

+

329 is_excluded = check(filtered[column]) 

+

330 filtered = filtered.loc[~is_excluded] 

+

331 

+

332 num_after = len(filtered) 

+

333 logger.info(f"Excluded {num_before - num_after} patients.") 

+

334 return filtered 

+

335 

+

336 

+

337if __name__ == "__main__": 

+

338 main = assemble_main(settings_cls=LyproxifyCLI, prog_name="lyproxify") 

+

339 main() 

+
+ + + diff --git a/htmlcov/z_9b7bcb970ba14d6a_split_py.html b/htmlcov/z_9b7bcb970ba14d6a_split_py.html new file mode 100644 index 0000000..b055382 --- /dev/null +++ b/htmlcov/z_9b7bcb970ba14d6a_split_py.html @@ -0,0 +1,170 @@ + + + + + Coverage for src/lyscripts/data/split.py: 53% + + + + + +
+
+

+ Coverage for src/lyscripts/data/split.py: + 53% +

+ +

+ 30 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Split a dataset into cross-validation folds based on params.yaml file.""" 

+

2 

+

3import warnings 

+

4from pathlib import Path 

+

5 

+

6import numpy as np 

+

7import pandas as pd 

+

8from loguru import logger 

+

9from pydantic import Field 

+

10 

+

11from lyscripts.cli import assemble_main 

+

12from lyscripts.configs import BaseCLI, CrossValidationConfig, DataConfig 

+

13from lyscripts.data.utils import save_table_to_csv 

+

14 

+

15warnings.simplefilter(action="ignore", category=FutureWarning) 

+

16 

+

17 

+

18class SplitCLI(BaseCLI): 

+

19 """Split a dataset into cross-validation folds.""" 

+

20 

+

21 input: DataConfig 

+

22 cross_validation: CrossValidationConfig = CrossValidationConfig() 

+

23 output_dir: Path = Field(description="The folder to store the split CSV files in.") 

+

24 

+

25 def cli_cmd(self) -> None: 

+

26 """Run the ``split`` subcommand. 

+

27 

+

28 This will load the dataset specified in the ``input`` argument and split it 

+

29 into the number of folds specified in the ``cross_validation`` argument. The 

+

30 resulting splits will be stored in the folder specified in the ``output_dir`` 

+

31 argument. 

+

32 """ 

+

33 logger.debug(self.model_dump_json(indent=2)) 

+

34 

+

35 self.output_dir.mkdir(parents=True, exist_ok=True) 

+

36 logger.info(f"Ensure output directory {self.output_dir} exists") 

+

37 

+

38 data = self.input.load() 

+

39 

+

40 shuffled_data = data.sample( 

+

41 frac=1.0, 

+

42 replace=False, 

+

43 random_state=self.cross_validation.seed, 

+

44 ).reset_index(drop=True) 

+

45 

+

46 split_datas = np.array_split( 

+

47 ary=shuffled_data, 

+

48 indices_or_sections=self.cross_validation.folds, 

+

49 ) 

+

50 for fold in range(self.cross_validation.folds): 

+

51 _train_datas = [ 

+

52 split_datas[i] for i in range(self.cross_validation.folds) if i != fold 

+

53 ] 

+

54 train_data = pd.concat( 

+

55 objs=_train_datas, 

+

56 axis="index", 

+

57 ignore_index=True, 

+

58 ) 

+

59 eval_data = split_datas[fold] 

+

60 

+

61 save_table_to_csv( 

+

62 file_path=self.output_dir / f"{fold}_train.csv", 

+

63 table=train_data, 

+

64 ) 

+

65 save_table_to_csv( 

+

66 file_path=self.output_dir / f"{fold}_eval.csv", 

+

67 table=eval_data, 

+

68 ) 

+

69 

+

70 

+

71if __name__ == "__main__": 

+

72 main = assemble_main(settings_cls=SplitCLI, prog_name="split") 

+

73 main() 

+
+ + + diff --git a/htmlcov/z_9b7bcb970ba14d6a_utils_py.html b/htmlcov/z_9b7bcb970ba14d6a_utils_py.html new file mode 100644 index 0000000..8524805 --- /dev/null +++ b/htmlcov/z_9b7bcb970ba14d6a_utils_py.html @@ -0,0 +1,113 @@ + + + + + Coverage for src/lyscripts/data/utils.py: 100% + + + + + +
+
+

+ Coverage for src/lyscripts/data/utils.py: + 100% +

+ +

+ 9 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.9.1, + created at 2025-06-26 14:44 +0000 +

+ +
+
+
+

1"""Utilities related to the commands for data cleaning and processing.""" 

+

2 

+

3from pathlib import Path 

+

4 

+

5import pandas as pd 

+

6from loguru import logger 

+

7 

+

8from lyscripts.decorators import check_output_dir_exists 

+

9 

+

10 

+

11@check_output_dir_exists 

+

12def save_table_to_csv(file_path: Path, table: pd.DataFrame): 

+

13 """Save a ``table`` to ``output_path``.""" 

+

14 shape = table.shape 

+

15 logger.info(f"Saving table with {shape=} to {file_path.resolve()}") 

+

16 table.to_csv(file_path, index=None) 

+
+ + + From 67d0f1d940c4e99f98f0a1f15539c783243e3147 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Jul 2025 06:01:16 +0000 Subject: [PATCH 2/5] Update coverage data --- README.md | 11 +- data.json | 2 +- htmlcov/class_index.html | 54 +- htmlcov/function_index.html | 102 +-- htmlcov/index.html | 33 +- htmlcov/status.json | 2 +- htmlcov/z_055061514423972c___init___py.html | 8 +- htmlcov/z_055061514423972c___main___py.html | 8 +- htmlcov/z_055061514423972c_posteriors_py.html | 8 +- .../z_055061514423972c_prevalences_py.html | 442 ++++++------ htmlcov/z_055061514423972c_priors_py.html | 8 +- htmlcov/z_055061514423972c_risks_py.html | 8 +- htmlcov/z_055061514423972c_utils_py.html | 8 +- htmlcov/z_5bf5c588c698c6cc___init___py.html | 8 +- htmlcov/z_5bf5c588c698c6cc___main___py.html | 8 +- htmlcov/z_5bf5c588c698c6cc__version_py.html | 8 +- htmlcov/z_5bf5c588c698c6cc_cli_py.html | 8 +- htmlcov/z_5bf5c588c698c6cc_configs_py.html | 8 +- htmlcov/z_5bf5c588c698c6cc_decorators_py.html | 8 +- htmlcov/z_5bf5c588c698c6cc_evaluate_py.html | 8 +- htmlcov/z_5bf5c588c698c6cc_plots_py.html | 8 +- htmlcov/z_5bf5c588c698c6cc_sample_py.html | 8 +- htmlcov/z_5bf5c588c698c6cc_schedule_py.html | 8 +- htmlcov/z_5bf5c588c698c6cc_schema_py.html | 8 +- htmlcov/z_5bf5c588c698c6cc_utils_py.html | 8 +- htmlcov/z_9b7bcb970ba14d6a___init___py.html | 58 +- htmlcov/z_9b7bcb970ba14d6a___main___py.html | 8 +- htmlcov/z_9b7bcb970ba14d6a_enhance_py.html | 12 +- htmlcov/z_9b7bcb970ba14d6a_fetch_py.html | 154 +++++ htmlcov/z_9b7bcb970ba14d6a_filter_py.html | 12 +- htmlcov/z_9b7bcb970ba14d6a_generate_py.html | 8 +- htmlcov/z_9b7bcb970ba14d6a_join_py.html | 99 +-- htmlcov/z_9b7bcb970ba14d6a_lyproxify_py.html | 648 +++++++++--------- htmlcov/z_9b7bcb970ba14d6a_split_py.html | 8 +- htmlcov/z_9b7bcb970ba14d6a_utils_py.html | 8 +- 35 files changed, 1003 insertions(+), 802 deletions(-) create mode 100644 htmlcov/z_9b7bcb970ba14d6a_fetch_py.html diff --git a/README.md b/README.md index 12a1fb9..fde690c 100644 --- a/README.md +++ b/README.md @@ -11,18 +11,19 @@ | src/lyscripts/compute/\_\_init\_\_.py | 9 | 1 | 89% | 21 | | src/lyscripts/compute/\_\_main\_\_.py | 5 | 5 | 0% | 3-8 | | src/lyscripts/compute/posteriors.py | 46 | 19 | 59% |97-137, 141-142 | -| src/lyscripts/compute/prevalences.py | 80 | 7 | 91% |58-60, 94-99, 232-233 | +| src/lyscripts/compute/prevalences.py | 82 | 7 | 91% |59-61, 95-100, 234-235 | | src/lyscripts/compute/priors.py | 35 | 2 | 94% | 110-111 | | src/lyscripts/compute/risks.py | 51 | 33 | 35% |47-65, 81-135, 139-140 | | src/lyscripts/compute/utils.py | 120 | 6 | 95% |95, 146, 177, 188, 240, 250 | | src/lyscripts/configs.py | 255 | 27 | 89% |90, 122, 165, 173, 217, 271, 277-278, 286, 472, 506-509, 514, 585, 624-637, 680 | -| src/lyscripts/data/\_\_init\_\_.py | 12 | 1 | 92% | 43 | +| src/lyscripts/data/\_\_init\_\_.py | 13 | 1 | 92% | 45 | | src/lyscripts/data/\_\_main\_\_.py | 18 | 18 | 0% | 3-36 | | src/lyscripts/data/enhance.py | 24 | 8 | 67% |39-58, 62-63 | +| src/lyscripts/data/fetch.py | 21 | 7 | 67% |42-52, 56-57 | | src/lyscripts/data/filter.py | 49 | 30 | 39% |43-66, 76-94, 98-99 | | src/lyscripts/data/generate.py | 39 | 4 | 90% |58, 63, 95-96 | -| src/lyscripts/data/join.py | 20 | 9 | 55% |59-72, 76-77 | -| src/lyscripts/data/lyproxify.py | 121 | 67 | 45% |29-32, 37-44, 88-117, 130-140, 171, 248-280, 291-305, 338-339 | +| src/lyscripts/data/join.py | 20 | 9 | 55% |60-73, 77-78 | +| src/lyscripts/data/lyproxify.py | 123 | 67 | 46% |31-34, 39-46, 90-119, 132-142, 173, 250-282, 293-307, 340-341 | | src/lyscripts/data/split.py | 30 | 14 | 53% |33-65, 72-73 | | src/lyscripts/data/utils.py | 9 | 0 | 100% | | | src/lyscripts/decorators.py | 41 | 4 | 90% | 53-55, 70 | @@ -32,7 +33,7 @@ | src/lyscripts/schedule.py | 29 | 13 | 55% |25-27, 35, 44-45, 73-80, 84-85 | | src/lyscripts/schema.py | 21 | 3 | 86% | 60-61, 65 | | src/lyscripts/utils.py | 84 | 5 | 94% |25, 141-142, 196-197 | -| **TOTAL** | **1551** | **392** | **75%** | | +| **TOTAL** | **1577** | **399** | **75%** | | ## Setup coverage badge diff --git a/data.json b/data.json index 1ec6703..a934360 100644 --- a/data.json +++ b/data.json @@ -1 +1 @@ -{"coverage": 74.72598323662153, "raw_data": {"meta": {"format": 3, "version": "7.9.1", "timestamp": "2025-06-26T14:44:06.796026", "branch_coverage": false, "show_contexts": false}, "files": {"src/lyscripts/__init__.py": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 20, 21, 22, 23, 25, 26, 27, 28, 29, 33, 35, 38, 39, 41, 45, 50, 51, 52, 53, 55, 60, 75], "summary": {"covered_lines": 27, "num_statements": 34, "percent_covered": 79.41176470588235, "percent_covered_display": "79", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [57, 58, 66, 68, 69, 70, 72], "excluded_lines": [], "functions": {"LyscriptsCLI.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [57, 58], "excluded_lines": []}, "LyscriptsCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [66, 68, 69, 70, 72], "excluded_lines": []}, "": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 20, 21, 22, 23, 25, 26, 27, 28, 29, 33, 35, 38, 39, 41, 45, 50, 51, 52, 53, 55, 60, 75], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"LyscriptsCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [57, 58, 66, 68, 69, 70, 72], "excluded_lines": []}, "": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 20, 21, 22, 23, 25, 26, 27, 28, 29, 33, 35, 38, 39, 41, 45, 50, 51, 52, 53, 55, 60, 75], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/lyscripts/__main__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [3, 5, 6], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [3, 5, 6], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [3, 5, 6], "excluded_lines": []}}}, "src/lyscripts/_version.py": {"executed_lines": [4, 6, 7, 13, 15, 16, 17, 18, 20, 21], "summary": {"covered_lines": 10, "num_statements": 13, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [8, 9, 11], "excluded_lines": [], "functions": {"": {"executed_lines": [4, 6, 7, 13, 15, 16, 17, 18, 20, 21], "summary": {"covered_lines": 10, "num_statements": 13, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [8, 9, 11], "excluded_lines": []}}, "classes": {"": {"executed_lines": [4, 6, 7, 13, 15, 16, 17, 18, 20, 21], "summary": {"covered_lines": 10, "num_statements": 13, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [8, 9, 11], "excluded_lines": []}}}, "src/lyscripts/cli.py": {"executed_lines": [1, 11, 12, 14, 15, 16, 17, 18, 21, 35, 37, 44, 46, 49, 70], "summary": {"covered_lines": 14, "num_statements": 26, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [61, 62, 63, 64, 65, 67, 81, 82, 83, 84, 85, 86], "excluded_lines": [], "functions": {"assemble_main": {"executed_lines": [35, 46], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "assemble_main.main": {"executed_lines": [37, 44], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "somewhat_safely_get_loglevel": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [61, 62, 63, 64, 65, 67], "excluded_lines": []}, "configure_logging": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [81, 82, 83, 84, 85, 86], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 14, 15, 16, 17, 18, 21, 49, 70], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 11, 12, 14, 15, 16, 17, 18, 21, 35, 37, 44, 46, 49, 70], "summary": {"covered_lines": 14, "num_statements": 26, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [61, 62, 63, 64, 65, 67, 81, 82, 83, 84, 85, 86], "excluded_lines": []}}}, "src/lyscripts/compute/__init__.py": {"executed_lines": [1, 6, 8, 11, 12, 14, 15, 16, 17, 19], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [21], "excluded_lines": [], "functions": {"ComputeCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [21], "excluded_lines": []}, "": {"executed_lines": [1, 6, 8, 11, 12, 14, 15, 16, 17, 19], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ComputeCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [21], "excluded_lines": []}, "": {"executed_lines": [1, 6, 8, 11, 12, 14, 15, 16, 17, 19], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/lyscripts/compute/__main__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [3, 4, 6, 7, 8], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [3, 4, 6, 7, 8], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [3, 4, 6, 7, 8], "excluded_lines": []}}}, "src/lyscripts/compute/posteriors.py": {"executed_lines": [1, 9, 11, 12, 13, 14, 15, 17, 18, 19, 20, 29, 32, 51, 52, 53, 54, 55, 57, 58, 60, 66, 75, 78, 79, 81, 87, 91, 140], "summary": {"covered_lines": 27, "num_statements": 46, "percent_covered": 58.69565217391305, "percent_covered_display": "59", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [97, 99, 102, 104, 105, 106, 107, 109, 110, 111, 113, 122, 123, 125, 135, 136, 137, 141, 142], "excluded_lines": [], "functions": {"compute_posteriors": {"executed_lines": [51, 52, 53, 54, 55, 57, 58, 60, 66, 75], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PosteriorsCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [97, 99, 102, 104, 105, 106, 107, 109, 110, 111, 113, 122, 123, 125, 135, 136, 137], "excluded_lines": []}, "": {"executed_lines": [1, 9, 11, 12, 13, 14, 15, 17, 18, 19, 20, 29, 32, 78, 79, 81, 87, 91, 140], "summary": {"covered_lines": 17, "num_statements": 19, "percent_covered": 89.47368421052632, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [141, 142], "excluded_lines": []}}, "classes": {"PosteriorsCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [97, 99, 102, 104, 105, 106, 107, 109, 110, 111, 113, 122, 123, 125, 135, 136, 137], "excluded_lines": []}, "": {"executed_lines": [1, 9, 11, 12, 13, 14, 15, 17, 18, 19, 20, 29, 32, 51, 52, 53, 54, 55, 57, 58, 60, 66, 75, 78, 79, 81, 87, 91, 140], "summary": {"covered_lines": 27, "num_statements": 29, "percent_covered": 93.10344827586206, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [141, 142], "excluded_lines": []}}}, "src/lyscripts/compute/prevalences.py": {"executed_lines": [1, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 28, 40, 43, 54, 55, 57, 62, 63, 64, 66, 72, 73, 78, 79, 81, 87, 101, 103, 106, 108, 109, 110, 111, 112, 113, 114, 117, 141, 142, 144, 145, 146, 148, 155, 161, 162, 164, 170, 173, 175, 177, 178, 181, 183, 184, 185, 186, 188, 189, 190, 192, 201, 202, 204, 214, 219, 220, 221, 222, 231], "summary": {"covered_lines": 73, "num_statements": 80, "percent_covered": 91.25, "percent_covered_display": "91", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [58, 59, 60, 94, 99, 232, 233], "excluded_lines": [], "functions": {"compute_prevalences": {"executed_lines": [54, 55, 57, 62, 63, 64, 66, 72, 73, 78, 79, 81, 87, 101, 103], "summary": {"covered_lines": 15, "num_statements": 20, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [58, 59, 60, 94, 99], "excluded_lines": []}, "generate_query_from_diagnosis": {"executed_lines": [108, 109, 110, 111, 112, 113, 114], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "observe_prevalence": {"executed_lines": [141, 142, 144, 145, 146, 148, 155], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PrevalencesCLI.cli_cmd": {"executed_lines": [177, 178, 181, 183, 184, 185, 186, 188, 189, 190, 192, 201, 202, 204, 214, 219, 220, 221, 222], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 28, 40, 43, 106, 117, 161, 162, 164, 170, 173, 175, 231], "summary": {"covered_lines": 25, "num_statements": 27, "percent_covered": 92.5925925925926, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [232, 233], "excluded_lines": []}}, "classes": {"PrevalencesCLI": {"executed_lines": [177, 178, 181, 183, 184, 185, 186, 188, 189, 190, 192, 201, 202, 204, 214, 219, 220, 221, 222], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 28, 40, 43, 54, 55, 57, 62, 63, 64, 66, 72, 73, 78, 79, 81, 87, 101, 103, 106, 108, 109, 110, 111, 112, 113, 114, 117, 141, 142, 144, 145, 146, 148, 155, 161, 162, 164, 170, 173, 175, 231], "summary": {"covered_lines": 54, "num_statements": 61, "percent_covered": 88.52459016393442, "percent_covered_display": "89", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [58, 59, 60, 94, 99, 232, 233], "excluded_lines": []}}}, "src/lyscripts/compute/priors.py": {"executed_lines": [1, 7, 9, 10, 11, 12, 14, 15, 16, 23, 26, 42, 43, 44, 46, 52, 53, 60, 63, 64, 66, 68, 84, 85, 86, 88, 89, 90, 92, 93, 94, 96, 105, 106, 109], "summary": {"covered_lines": 33, "num_statements": 35, "percent_covered": 94.28571428571429, "percent_covered_display": "94", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [110, 111], "excluded_lines": [], "functions": {"compute_priors": {"executed_lines": [42, 43, 44, 46, 52, 53, 60], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PriorsCLI.cli_cmd": {"executed_lines": [84, 85, 86, 88, 89, 90, 92, 93, 94, 96, 105, 106], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 7, 9, 10, 11, 12, 14, 15, 16, 23, 26, 63, 64, 66, 68, 109], "summary": {"covered_lines": 14, "num_statements": 16, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [110, 111], "excluded_lines": []}}, "classes": {"PriorsCLI": {"executed_lines": [84, 85, 86, 88, 89, 90, 92, 93, 94, 96, 105, 106], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 7, 9, 10, 11, 12, 14, 15, 16, 23, 26, 42, 43, 44, 46, 52, 53, 60, 63, 64, 66, 68, 109], "summary": {"covered_lines": 21, "num_statements": 23, "percent_covered": 91.30434782608695, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [110, 111], "excluded_lines": []}}}, "src/lyscripts/compute/risks.py": {"executed_lines": [1, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 29, 32, 68, 69, 71, 77, 79, 138], "summary": {"covered_lines": 18, "num_statements": 51, "percent_covered": 35.294117647058826, "percent_covered_display": "35", "missing_lines": 33, "excluded_lines": 0}, "missing_lines": [47, 48, 49, 50, 52, 53, 55, 61, 65, 81, 82, 85, 87, 88, 89, 90, 91, 93, 94, 95, 97, 106, 107, 109, 119, 120, 122, 132, 133, 134, 135, 139, 140], "excluded_lines": [], "functions": {"compute_risks": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [47, 48, 49, 50, 52, 53, 55, 61, 65], "excluded_lines": []}, "RisksCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [81, 82, 85, 87, 88, 89, 90, 91, 93, 94, 95, 97, 106, 107, 109, 119, 120, 122, 132, 133, 134, 135], "excluded_lines": []}, "": {"executed_lines": [1, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 29, 32, 68, 69, 71, 77, 79, 138], "summary": {"covered_lines": 18, "num_statements": 20, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [139, 140], "excluded_lines": []}}, "classes": {"RisksCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [81, 82, 85, 87, 88, 89, 90, 91, 93, 94, 95, 97, 106, 107, 109, 119, 120, 122, 132, 133, 134, 135], "excluded_lines": []}, "": {"executed_lines": [1, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 29, 32, 68, 69, 71, 77, 79, 138], "summary": {"covered_lines": 18, "num_statements": 29, "percent_covered": 62.06896551724138, "percent_covered_display": "62", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [47, 48, 49, 50, 52, 53, 55, 61, 65, 139, 140], "excluded_lines": []}}}, "src/lyscripts/compute/utils.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 14, 24, 25, 27, 28, 29, 36, 40, 44, 47, 49, 55, 57, 58, 59, 60, 62, 63, 66, 68, 69, 70, 71, 72, 73, 74, 77, 92, 94, 97, 98, 99, 101, 104, 106, 107, 108, 111, 112, 115, 116, 118, 121, 128, 145, 148, 149, 151, 153, 155, 156, 158, 159, 161, 163, 165, 166, 168, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 187, 189, 191, 194, 210, 211, 212, 213, 214, 215, 216, 217, 219, 222, 239, 242, 243, 244, 246, 247, 248, 249, 252, 254, 257, 259, 260, 261, 263, 264, 265, 266, 267, 269, 271, 272, 273, 275, 276], "summary": {"covered_lines": 114, "num_statements": 120, "percent_covered": 95.0, "percent_covered_display": "95", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [95, 146, 177, 188, 240, 250], "excluded_lines": [], "functions": {"is_hdf5_compatible": {"executed_lines": [49], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "to_hdf5_attrs": {"executed_lines": [57, 58, 59, 60, 62, 63], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "from_hdf5_attrs": {"executed_lines": [68, 69, 70, 71, 72, 73, 74], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "extract_modalities": {"executed_lines": [92, 94, 97, 98, 99, 101], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [95], "excluded_lines": []}, "ensure_parent_dir": {"executed_lines": [106, 107, 108], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "HDF5FileStorage._get_dataset": {"executed_lines": [145, 148, 149], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [146], "excluded_lines": []}, "HDF5FileStorage.load": {"executed_lines": [153, 155, 156, 158, 159], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "HDF5FileStorage.get_attrs": {"executed_lines": [163, 165, 166, 168, 169], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "HDF5FileStorage.save": {"executed_lines": [173, 175, 176, 178, 180], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [177], "excluded_lines": []}, "HDF5FileStorage.set_attrs": {"executed_lines": [184, 186, 187, 189, 191], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [188], "excluded_lines": []}, "reduce_pattern": {"executed_lines": [210, 211, 212, 213, 214, 215, 216, 217, 219], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "complete_pattern": {"executed_lines": [239, 242, 243, 244, 246, 247, 248, 249, 252, 254], "summary": {"covered_lines": 10, "num_statements": 12, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [240, 250], "excluded_lines": []}, "get_cached": {"executed_lines": [259, 260, 261, 263, 264, 275, 276], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_cached.log_cache_info_wrapper": {"executed_lines": [265, 266, 267, 269, 271, 272, 273], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 14, 24, 25, 27, 28, 29, 36, 40, 44, 47, 55, 66, 77, 104, 111, 112, 115, 116, 118, 121, 128, 151, 161, 171, 182, 194, 222, 257], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"BaseComputeCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "HDF5FileStorage": {"executed_lines": [145, 148, 149, 153, 155, 156, 158, 159, 163, 165, 166, 168, 169, 173, 175, 176, 178, 180, 184, 186, 187, 189, 191], "summary": {"covered_lines": 23, "num_statements": 26, "percent_covered": 88.46153846153847, "percent_covered_display": "88", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [146, 177, 188], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 14, 24, 25, 27, 28, 29, 36, 40, 44, 47, 49, 55, 57, 58, 59, 60, 62, 63, 66, 68, 69, 70, 71, 72, 73, 74, 77, 92, 94, 97, 98, 99, 101, 104, 106, 107, 108, 111, 112, 115, 116, 118, 121, 128, 151, 161, 171, 182, 194, 210, 211, 212, 213, 214, 215, 216, 217, 219, 222, 239, 242, 243, 244, 246, 247, 248, 249, 252, 254, 257, 259, 260, 261, 263, 264, 265, 266, 267, 269, 271, 272, 273, 275, 276], "summary": {"covered_lines": 91, "num_statements": 94, "percent_covered": 96.80851063829788, "percent_covered_display": "97", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [95, 240, 250], "excluded_lines": []}}}, "src/lyscripts/configs.py": {"executed_lines": [1, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 39, 44, 46, 48, 51, 56, 57, 59, 63, 69, 70, 72, 78, 82, 87, 89, 92, 94, 96, 102, 104, 107, 108, 110, 115, 120, 128, 129, 131, 135, 139, 145, 146, 148, 153, 159, 161, 162, 164, 167, 168, 170, 171, 176, 177, 179, 182, 186, 187, 189, 190, 202, 204, 205, 206, 208, 209, 211, 214, 216, 219, 220, 222, 225, 226, 228, 232, 236, 240, 244, 253, 258, 259, 261, 270, 273, 275, 276, 280, 281, 282, 283, 285, 288, 296, 298, 299, 306, 307, 316, 321, 325, 332, 336, 341, 343, 348, 349, 350, 355, 357, 359, 360, 362, 363, 364, 366, 367, 368, 370, 372, 379, 380, 381, 387, 390, 391, 393, 396, 400, 404, 412, 416, 420, 424, 431, 435, 439, 443, 451, 457, 464, 466, 467, 469, 470, 475, 476, 478, 482, 487, 491, 495, 496, 498, 500, 501, 503, 505, 511, 513, 519, 521, 522, 523, 524, 525, 526, 529, 550, 551, 553, 554, 555, 561, 562, 565, 572, 573, 574, 576, 578, 579, 580, 581, 582, 583, 587, 588, 589, 590, 592, 594, 595, 598, 604, 605, 606, 608, 609, 610, 612, 613, 616, 640, 643, 644, 657, 672, 673, 675, 677, 678, 679, 684, 686, 688, 692, 693, 699, 701, 703, 713, 714, 716, 718, 728, 729, 738, 743, 744], "summary": {"covered_lines": 228, "num_statements": 255, "percent_covered": 89.41176470588235, "percent_covered_display": "89", "missing_lines": 27, "excluded_lines": 0}, "missing_lines": [90, 122, 165, 173, 217, 271, 277, 278, 286, 472, 506, 507, 509, 514, 585, 624, 625, 627, 628, 629, 631, 632, 633, 635, 636, 637, 680], "excluded_lines": [], "functions": {"DataConfig.load": {"executed_lines": [89, 92], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [90], "excluded_lines": []}, "DataConfig.get_load_kwargs": {"executed_lines": [96], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "check_pattern": {"executed_lines": [104], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DiagnosisConfig.to_involvement": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [122], "excluded_lines": []}, "retrieve_graph_representation": {"executed_lines": [161, 162, 164, 167, 168, 170, 171], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [165, 173], "excluded_lines": []}, "GraphConfig.from_model": {"executed_lines": [189, 190], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "has_model_symbol": {"executed_lines": [204, 205, 206, 208, 209, 211], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_symmetry_kwargs": {"executed_lines": [216, 219, 220, 222], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [217], "excluded_lines": []}, "ModelConfig.from_model": {"executed_lines": [261, 270, 273, 275, 276, 280, 281, 282, 283, 285, 288], "summary": {"covered_lines": 11, "num_statements": 15, "percent_covered": 73.33333333333333, "percent_covered_display": "73", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [271, 277, 278, 286], "excluded_lines": []}, "modalityconfig_from_model": {"executed_lines": [298, 299], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DeprecatedModelConfig.model_post_init": {"executed_lines": [343, 348, 349, 350, 355], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DeprecatedModelConfig.translate": {"executed_lines": [359, 360, 362, 363, 364, 366, 367, 368, 370, 372, 379, 380, 381, 387], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SamplingConfig.load": {"executed_lines": [457], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "map_to_optional_bool": {"executed_lines": [466, 467, 469, 470], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [472], "excluded_lines": []}, "ScenarioConfig.model_post_init": {"executed_lines": [500, 501], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ScenarioConfig.interpolate": {"executed_lines": [505], "summary": {"covered_lines": 1, "num_statements": 4, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [506, 507, 509], "excluded_lines": []}, "ScenarioConfig.normalize": {"executed_lines": [513], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [514], "excluded_lines": []}, "_construct_model_from_external": {"executed_lines": [521, 522, 523, 524, 525, 526], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "construct_model": {"executed_lines": [550, 551, 553, 554, 555, 561, 562], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "add_distributions": {"executed_lines": [572, 573, 574, 576, 578, 579, 580, 581, 582, 583, 587, 588, 589, 590, 592, 594, 595], "summary": {"covered_lines": 17, "num_statements": 18, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [585], "excluded_lines": []}, "add_modalities": {"executed_lines": [604, 605, 606, 608, 609, 610, 612, 613], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "add_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [624, 625, 627, 628, 629, 631, 632, 633, 635, 636, 637], "excluded_lines": []}, "DynamicYamlConfigSettingsSource.__init__": {"executed_lines": [672, 673], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DynamicYamlConfigSettingsSource._read_file": {"executed_lines": [677, 678, 679, 684], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [680], "excluded_lines": []}, "DynamicYamlConfigSettingsSource.__call__": {"executed_lines": [688, 692, 693, 699], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DynamicYamlConfigSettingsSource.__repr__": {"executed_lines": [703], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BaseCLI.settings_customise_sources": {"executed_lines": [738, 743, 744], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 39, 44, 46, 48, 51, 56, 57, 59, 63, 69, 70, 72, 78, 82, 87, 94, 102, 107, 108, 110, 115, 120, 128, 129, 131, 135, 139, 145, 146, 148, 153, 159, 176, 177, 179, 182, 186, 187, 202, 214, 225, 226, 228, 232, 236, 240, 244, 253, 258, 259, 296, 306, 307, 316, 321, 325, 332, 336, 341, 357, 390, 391, 393, 396, 400, 404, 412, 416, 420, 424, 431, 435, 439, 443, 451, 464, 475, 476, 478, 482, 487, 491, 495, 496, 498, 503, 511, 519, 529, 565, 598, 616, 640, 643, 644, 657, 675, 686, 701, 713, 714, 716, 718, 728, 729], "summary": {"covered_lines": 112, "num_statements": 112, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"CrossValidationConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DataConfig": {"executed_lines": [89, 92, 96], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [90], "excluded_lines": []}, "DiagnosisConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [122], "excluded_lines": []}, "DistributionConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "InvolvementConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "GraphConfig": {"executed_lines": [189, 190], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ModelConfig": {"executed_lines": [261, 270, 273, 275, 276, 280, 281, 282, 283, 285, 288], "summary": {"covered_lines": 11, "num_statements": 15, "percent_covered": 73.33333333333333, "percent_covered_display": "73", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [271, 277, 278, 286], "excluded_lines": []}, "DeprecatedModelConfig": {"executed_lines": [343, 348, 349, 350, 355, 359, 360, 362, 363, 364, 366, 367, 368, 370, 372, 379, 380, 381, 387], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SamplingConfig": {"executed_lines": [457], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ScenarioConfig": {"executed_lines": [500, 501, 505, 513], "summary": {"covered_lines": 4, "num_statements": 8, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [506, 507, 509, 514], "excluded_lines": []}, "DynamicYamlConfigSettingsSource": {"executed_lines": [672, 673, 677, 678, 679, 684, 688, 692, 693, 699, 703], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [680], "excluded_lines": []}, "BaseCLI": {"executed_lines": [738, 743, 744], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 39, 44, 46, 48, 51, 56, 57, 59, 63, 69, 70, 72, 78, 82, 87, 94, 102, 104, 107, 108, 110, 115, 120, 128, 129, 131, 135, 139, 145, 146, 148, 153, 159, 161, 162, 164, 167, 168, 170, 171, 176, 177, 179, 182, 186, 187, 202, 204, 205, 206, 208, 209, 211, 214, 216, 219, 220, 222, 225, 226, 228, 232, 236, 240, 244, 253, 258, 259, 296, 298, 299, 306, 307, 316, 321, 325, 332, 336, 341, 357, 390, 391, 393, 396, 400, 404, 412, 416, 420, 424, 431, 435, 439, 443, 451, 464, 466, 467, 469, 470, 475, 476, 478, 482, 487, 491, 495, 496, 498, 503, 511, 519, 521, 522, 523, 524, 525, 526, 529, 550, 551, 553, 554, 555, 561, 562, 565, 572, 573, 574, 576, 578, 579, 580, 581, 582, 583, 587, 588, 589, 590, 592, 594, 595, 598, 604, 605, 606, 608, 609, 610, 612, 613, 616, 640, 643, 644, 657, 675, 686, 701, 713, 714, 716, 718, 728, 729], "summary": {"covered_lines": 174, "num_statements": 190, "percent_covered": 91.57894736842105, "percent_covered_display": "92", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [165, 173, 217, 472, 585, 624, 625, 627, 628, 629, 631, 632, 633, 635, 636, 637], "excluded_lines": []}}}, "src/lyscripts/data/__init__.py": {"executed_lines": [1, 17, 19, 28, 31, 32, 34, 35, 36, 37, 38, 39, 41], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [43], "excluded_lines": [], "functions": {"DataCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [43], "excluded_lines": []}, "": {"executed_lines": [1, 17, 19, 28, 31, 32, 34, 35, 36, 37, 38, 39, 41], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DataCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [43], "excluded_lines": []}, "": {"executed_lines": [1, 17, 19, 28, 31, 32, 34, 35, 36, 37, 38, 39, 41], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/lyscripts/data/__main__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 7, 10, 13, 15, 20, 21, 25, 26, 27, 28, 29, 31, 32, 35, 36], "excluded_lines": [], "functions": {"main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [15, 20, 21, 25, 26, 27, 28, 29, 31, 32], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 7, 10, 13, 35, 36], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 7, 10, 13, 15, 20, 21, 25, 26, 27, 28, 29, 31, 32, 35, 36], "excluded_lines": []}}}, "src/lyscripts/data/enhance.py": {"executed_lines": [1, 7, 9, 10, 11, 13, 14, 15, 18, 19, 21, 22, 23, 24, 25, 30, 32, 61], "summary": {"covered_lines": 16, "num_statements": 24, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [39, 41, 42, 44, 49, 58, 62, 63], "excluded_lines": [], "functions": {"EnhanceCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [39, 41, 42, 44, 49, 58], "excluded_lines": []}, "": {"executed_lines": [1, 7, 9, 10, 11, 13, 14, 15, 18, 19, 21, 22, 23, 24, 25, 30, 32, 61], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [62, 63], "excluded_lines": []}}, "classes": {"EnhanceCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [39, 41, 42, 44, 49, 58], "excluded_lines": []}, "": {"executed_lines": [1, 7, 9, 10, 11, 13, 14, 15, 18, 19, 21, 22, 23, 24, 25, 30, 32, 61], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [62, 63], "excluded_lines": []}}}, "src/lyscripts/data/filter.py": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 15, 16, 17, 20, 21, 23, 24, 28, 35, 38, 39, 41, 68, 97], "summary": {"covered_lines": 19, "num_statements": 49, "percent_covered": 38.775510204081634, "percent_covered_display": "39", "missing_lines": 30, "excluded_lines": 0}, "missing_lines": [43, 44, 45, 46, 47, 49, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 66, 76, 78, 79, 84, 85, 87, 88, 89, 91, 92, 94, 98, 99], "excluded_lines": [], "functions": {"FilterCLI.model_post_init": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [43, 44, 45, 46, 47, 49, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 66], "excluded_lines": []}, "FilterCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [76, 78, 79, 84, 85, 87, 88, 89, 91, 92, 94], "excluded_lines": []}, "": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 15, 16, 17, 20, 21, 23, 24, 28, 35, 38, 39, 41, 68, 97], "summary": {"covered_lines": 19, "num_statements": 21, "percent_covered": 90.47619047619048, "percent_covered_display": "90", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [98, 99], "excluded_lines": []}}, "classes": {"FilterCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 28, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [43, 44, 45, 46, 47, 49, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 66, 76, 78, 79, 84, 85, 87, 88, 89, 91, 92, 94], "excluded_lines": []}, "": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 15, 16, 17, 20, 21, 23, 24, 28, 35, 38, 39, 41, 68, 97], "summary": {"covered_lines": 19, "num_statements": 21, "percent_covered": 90.47619047619048, "percent_covered_display": "90", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [98, 99], "excluded_lines": []}}}, "src/lyscripts/data/generate.py": {"executed_lines": [1, 11, 12, 13, 14, 16, 17, 26, 29, 30, 32, 33, 34, 41, 47, 48, 49, 50, 51, 53, 55, 56, 57, 60, 62, 65, 67, 76, 78, 79, 80, 81, 82, 84, 89, 91, 94], "summary": {"covered_lines": 35, "num_statements": 39, "percent_covered": 89.74358974358974, "percent_covered_display": "90", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [58, 63, 95, 96], "excluded_lines": [], "functions": {"GenerateCLI.model_post_init": {"executed_lines": [55, 56, 57, 60, 62, 65], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [58, 63], "excluded_lines": []}, "GenerateCLI.cli_cmd": {"executed_lines": [76, 78, 79, 80, 81, 82, 84, 89, 91], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 13, 14, 16, 17, 26, 29, 30, 32, 33, 34, 41, 47, 48, 49, 50, 51, 53, 67, 94], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [95, 96], "excluded_lines": []}}, "classes": {"GenerateCLI": {"executed_lines": [55, 56, 57, 60, 62, 65, 76, 78, 79, 80, 81, 82, 84, 89, 91], "summary": {"covered_lines": 15, "num_statements": 17, "percent_covered": 88.23529411764706, "percent_covered_display": "88", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [58, 63], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 13, 14, 16, 17, 26, 29, 30, 32, 33, 34, 41, 47, 48, 49, 50, 51, 53, 67, 94], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [95, 96], "excluded_lines": []}}}, "src/lyscripts/data/join.py": {"executed_lines": [1, 3, 5, 6, 8, 9, 10, 13, 14, 16, 17, 19, 75], "summary": {"covered_lines": 11, "num_statements": 20, "percent_covered": 55.0, "percent_covered_display": "55", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [59, 61, 62, 63, 64, 66, 72, 76, 77], "excluded_lines": [], "functions": {"JoinCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [59, 61, 62, 63, 64, 66, 72], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 8, 9, 10, 13, 14, 16, 17, 19, 75], "summary": {"covered_lines": 11, "num_statements": 13, "percent_covered": 84.61538461538461, "percent_covered_display": "85", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [76, 77], "excluded_lines": []}}, "classes": {"JoinCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [59, 61, 62, 63, 64, 66, 72], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 8, 9, 10, 13, 14, 16, 17, 19, 75], "summary": {"covered_lines": 11, "num_statements": 13, "percent_covered": 84.61538461538461, "percent_covered_display": "85", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [76, 77], "excluded_lines": []}}}, "src/lyscripts/data/lyproxify.py": {"executed_lines": [1, 10, 11, 12, 13, 15, 16, 17, 19, 20, 21, 22, 24, 27, 35, 47, 48, 50, 51, 55, 65, 72, 76, 78, 120, 121, 124, 143, 160, 161, 162, 163, 165, 167, 174, 197, 198, 199, 200, 201, 202, 203, 204, 206, 208, 211, 283, 308, 325, 326, 328, 329, 330, 332, 333, 334, 337], "summary": {"covered_lines": 54, "num_statements": 121, "percent_covered": 44.62809917355372, "percent_covered_display": "45", "missing_lines": 67, "excluded_lines": 0}, "missing_lines": [29, 30, 32, 37, 38, 39, 41, 42, 44, 88, 90, 94, 100, 101, 102, 103, 104, 106, 107, 108, 109, 111, 112, 114, 115, 117, 130, 132, 133, 134, 139, 140, 171, 248, 250, 251, 253, 254, 256, 257, 258, 259, 260, 261, 262, 263, 265, 266, 269, 270, 274, 279, 280, 291, 292, 293, 295, 296, 297, 298, 300, 301, 302, 304, 305, 338, 339], "excluded_lines": [], "functions": {"ensure_python_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [29, 30, 32], "excluded_lines": []}, "ensure_column_map": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [37, 38, 39, 41, 42, 44], "excluded_lines": []}, "LyproxifyCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [88, 90, 94, 100, 101, 102, 103, 104, 106, 107, 108, 109, 111, 112, 114, 115, 117], "excluded_lines": []}, "clean_header": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [130, 132, 133, 134, 139, 140], "excluded_lines": []}, "get_instruction_depth": {"executed_lines": [160, 161, 162, 163, 165, 167], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [171], "excluded_lines": []}, "generate_markdown_docs": {"executed_lines": [197, 198, 199, 200, 201, 202, 203, 204, 206, 208], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "transform_to_lyprox": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [248, 250, 251, 253, 254, 256, 257, 258, 259, 260, 261, 262, 263, 265, 266, 269, 270, 274, 279, 280], "excluded_lines": []}, "leftright_to_ipsicontra": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [291, 292, 293, 295, 296, 297, 298, 300, 301, 302, 304, 305], "excluded_lines": []}, "exclude_patients": {"executed_lines": [325, 326, 328, 329, 330, 332, 333, 334], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 10, 11, 12, 13, 15, 16, 17, 19, 20, 21, 22, 24, 27, 35, 47, 48, 50, 51, 55, 65, 72, 76, 78, 120, 121, 124, 143, 174, 211, 283, 308, 337], "summary": {"covered_lines": 30, "num_statements": 32, "percent_covered": 93.75, "percent_covered_display": "94", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [338, 339], "excluded_lines": []}}, "classes": {"LyproxifyCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [88, 90, 94, 100, 101, 102, 103, 104, 106, 107, 108, 109, 111, 112, 114, 115, 117], "excluded_lines": []}, "ParsingError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 10, 11, 12, 13, 15, 16, 17, 19, 20, 21, 22, 24, 27, 35, 47, 48, 50, 51, 55, 65, 72, 76, 78, 120, 121, 124, 143, 160, 161, 162, 163, 165, 167, 174, 197, 198, 199, 200, 201, 202, 203, 204, 206, 208, 211, 283, 308, 325, 326, 328, 329, 330, 332, 333, 334, 337], "summary": {"covered_lines": 54, "num_statements": 104, "percent_covered": 51.92307692307692, "percent_covered_display": "52", "missing_lines": 50, "excluded_lines": 0}, "missing_lines": [29, 30, 32, 37, 38, 39, 41, 42, 44, 130, 132, 133, 134, 139, 140, 171, 248, 250, 251, 253, 254, 256, 257, 258, 259, 260, 261, 262, 263, 265, 266, 269, 270, 274, 279, 280, 291, 292, 293, 295, 296, 297, 298, 300, 301, 302, 304, 305, 338, 339], "excluded_lines": []}}}, "src/lyscripts/data/split.py": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 18, 19, 21, 22, 23, 25, 71], "summary": {"covered_lines": 16, "num_statements": 30, "percent_covered": 53.333333333333336, "percent_covered_display": "53", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [33, 35, 36, 38, 40, 46, 50, 51, 54, 59, 61, 65, 72, 73], "excluded_lines": [], "functions": {"SplitCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [33, 35, 36, 38, 40, 46, 50, 51, 54, 59, 61, 65], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 18, 19, 21, 22, 23, 25, 71], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [72, 73], "excluded_lines": []}}, "classes": {"SplitCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [33, 35, 36, 38, 40, 46, 50, 51, 54, 59, 61, 65], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 18, 19, 21, 22, 23, 25, 71], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [72, 73], "excluded_lines": []}}}, "src/lyscripts/data/utils.py": {"executed_lines": [1, 3, 5, 6, 8, 11, 12, 14, 15, 16], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"save_table_to_csv": {"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}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 8, 11, 12], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 8, 11, 12, 14, 15, 16], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/lyscripts/decorators.py": {"executed_lines": [1, 8, 9, 10, 11, 12, 13, 16, 18, 19, 20, 23, 30, 33, 34, 36, 37, 38, 39, 41, 42, 51, 57, 59, 62, 65, 66, 68, 69, 72, 74, 77, 80, 81, 83, 84, 86, 88], "summary": {"covered_lines": 37, "num_statements": 41, "percent_covered": 90.2439024390244, "percent_covered_display": "90", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [53, 54, 55, 70], "excluded_lines": [], "functions": {"assemble_signature": {"executed_lines": [18, 19, 20], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "log_state": {"executed_lines": [30, 59], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "log_state.log_decorator": {"executed_lines": [33, 34, 57], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "log_state.log_decorator.wrapper": {"executed_lines": [36, 37, 38, 39, 41, 42, 51], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [53, 54, 55], "excluded_lines": []}, "check_input_file_exists": {"executed_lines": [65, 66, 74], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "check_input_file_exists.inner": {"executed_lines": [68, 69, 72], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [70], "excluded_lines": []}, "check_output_dir_exists": {"executed_lines": [80, 81, 88], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "check_output_dir_exists.inner": {"executed_lines": [83, 84, 86], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 8, 9, 10, 11, 12, 13, 16, 23, 62, 77], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 8, 9, 10, 11, 12, 13, 16, 18, 19, 20, 23, 30, 33, 34, 36, 37, 38, 39, 41, 42, 51, 57, 59, 62, 65, 66, 68, 69, 72, 74, 77, 80, 81, 83, 84, 86, 88], "summary": {"covered_lines": 37, "num_statements": 41, "percent_covered": 90.2439024390244, "percent_covered_display": "90", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [53, 54, 55, 70], "excluded_lines": []}}}, "src/lyscripts/evaluate.py": {"executed_lines": [1, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 21, 24, 38, 73, 90, 112, 144, 207], "summary": {"covered_lines": 18, "num_statements": 75, "percent_covered": 24.0, "percent_covered_display": "24", "missing_lines": 57, "excluded_lines": 0}, "missing_lines": [29, 35, 43, 48, 50, 57, 63, 70, 87, 104, 105, 106, 107, 108, 109, 120, 121, 123, 124, 129, 130, 131, 133, 134, 135, 137, 138, 139, 141, 146, 148, 149, 150, 151, 152, 155, 156, 163, 169, 171, 181, 182, 185, 186, 187, 190, 191, 193, 198, 199, 201, 202, 204, 208, 209, 211, 212], "excluded_lines": [], "functions": {"_add_parser": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [29, 35], "excluded_lines": []}, "_add_arguments": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [43, 48, 50, 57, 63, 70], "excluded_lines": []}, "comp_bic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [87], "excluded_lines": []}, "compute_evidence": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [104, 105, 106, 107, 108, 109], "excluded_lines": []}, "compute_ti_results": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [120, 121, 123, 124, 129, 130, 131, 133, 134, 135, 137, 138, 139, 141], "excluded_lines": []}, "main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 0}, "missing_lines": [146, 148, 149, 150, 151, 152, 155, 156, 163, 169, 171, 181, 182, 185, 186, 187, 190, 191, 193, 198, 199, 201, 202, 204], "excluded_lines": []}, "": {"executed_lines": [1, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 21, 24, 38, 73, 90, 112, 144, 207], "summary": {"covered_lines": 18, "num_statements": 22, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [208, 209, 211, 212], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 21, 24, 38, 73, 90, 112, 144, 207], "summary": {"covered_lines": 18, "num_statements": 75, "percent_covered": 24.0, "percent_covered_display": "24", "missing_lines": 57, "excluded_lines": 0}, "missing_lines": [29, 35, 43, 48, 50, 57, 63, 70, 87, 104, 105, 106, 107, 108, 109, 120, 121, 123, 124, 129, 130, 131, 133, 134, 135, 137, 138, 139, 141, 146, 148, 149, 150, 151, 152, 155, 156, 163, 169, 171, 181, 182, 185, 186, 187, 190, 191, 193, 198, 199, 201, 202, 204, 208, 209, 211, 212], "excluded_lines": []}}}, "src/lyscripts/plots.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 25, 30, 37, 38, 41, 50, 59, 61, 64, 66, 69, 74, 75, 76, 77, 78, 81, 84, 85, 87, 88, 89, 91, 92, 96, 97, 101, 102, 106, 109, 110, 112, 115, 116, 118, 120, 121, 123, 125, 126, 135, 136, 137, 138, 139, 140, 142, 144, 146, 148, 150, 152, 154, 155, 157, 158, 160, 163, 164, 166, 167, 169, 170, 179, 180, 181, 182, 183, 184, 190, 198, 199, 201, 202, 204, 206, 208, 216, 218, 225, 227, 234, 239, 240, 241, 243, 244, 246, 247, 249, 252, 268, 269, 270, 271, 273, 274, 275, 276, 279, 281, 282, 288, 289, 290, 291, 294, 303, 306, 307, 310, 311, 314, 335, 338, 340, 343, 345, 354, 355, 357, 358, 360, 363, 395, 396, 397, 402, 403, 404, 410, 411], "summary": {"covered_lines": 143, "num_statements": 166, "percent_covered": 86.144578313253, "percent_covered_display": "86", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [26, 27, 46, 47, 56, 94, 99, 104, 185, 186, 336, 341, 370, 375, 377, 378, 380, 381, 382, 383, 385, 392, 399], "excluded_lines": [], "functions": {"floor_at_decimal": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [46, 47], "excluded_lines": []}, "ceil_at_decimal": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [56], "excluded_lines": []}, "floor_to_step": {"executed_lines": [61], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ceil_to_step": {"executed_lines": [66], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "clean_and_check": {"executed_lines": [74, 75, 76, 77, 78], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AbstractDistribution.draw": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [94], "excluded_lines": []}, "AbstractDistribution.left_percentile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [99], "excluded_lines": []}, "AbstractDistribution.right_percentile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [104], "excluded_lines": []}, "AbstractDistribution._get_label": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AbstractDistribution.label": {"executed_lines": [112], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.values": {"executed_lines": [123], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.from_hdf5": {"executed_lines": [135, 136, 137, 138, 139, 140], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.left_percentile": {"executed_lines": [144], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.right_percentile": {"executed_lines": [148], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.draw": {"executed_lines": [152, 154, 155, 157, 158, 160], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.from_hdf5": {"executed_lines": [179, 180, 181, 182, 183, 184, 190], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [185, 186], "excluded_lines": []}, "BetaPosterior._get_label": {"executed_lines": [199], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.num_fail": {"executed_lines": [204], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.pdf": {"executed_lines": [208], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.left_percentile": {"executed_lines": [218], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.right_percentile": {"executed_lines": [227], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.draw": {"executed_lines": [239, 240, 241, 243, 244, 246, 247, 249], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_size": {"executed_lines": [268, 269, 270, 271, 273, 274, 275, 276], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_label": {"executed_lines": [281, 282, 288, 289, 290, 291], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_xlims": {"executed_lines": [303, 306, 307, 310, 311], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "draw": {"executed_lines": [335, 338, 340, 343, 345, 354, 355, 357, 358, 360], "summary": {"covered_lines": 10, "num_statements": 12, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [336, 341], "excluded_lines": []}, "split_legends": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [370, 375, 377, 378, 380, 381, 382, 383, 385, 392], "excluded_lines": []}, "use_mpl_stylesheet": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [399], "excluded_lines": []}, "save_figure": {"executed_lines": [410, 411], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 25, 30, 37, 38, 41, 50, 59, 64, 69, 81, 84, 85, 87, 88, 89, 91, 92, 96, 97, 101, 102, 106, 109, 110, 115, 116, 118, 120, 121, 125, 126, 142, 146, 150, 163, 164, 166, 167, 169, 170, 198, 201, 202, 206, 216, 225, 234, 252, 279, 294, 314, 363, 395, 396, 397, 402, 403, 404], "summary": {"covered_lines": 69, "num_statements": 71, "percent_covered": 97.1830985915493, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [26, 27], "excluded_lines": []}}, "classes": {"AbstractDistribution": {"executed_lines": [112], "summary": {"covered_lines": 1, "num_statements": 4, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [94, 99, 104], "excluded_lines": []}, "Histogram": {"executed_lines": [123, 135, 136, 137, 138, 139, 140, 144, 148, 152, 154, 155, 157, 158, 160], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior": {"executed_lines": [179, 180, 181, 182, 183, 184, 190, 199, 204, 208, 218, 227, 239, 240, 241, 243, 244, 246, 247, 249], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [185, 186], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 25, 30, 37, 38, 41, 50, 59, 61, 64, 66, 69, 74, 75, 76, 77, 78, 81, 84, 85, 87, 88, 89, 91, 92, 96, 97, 101, 102, 106, 109, 110, 115, 116, 118, 120, 121, 125, 126, 142, 146, 150, 163, 164, 166, 167, 169, 170, 198, 201, 202, 206, 216, 225, 234, 252, 268, 269, 270, 271, 273, 274, 275, 276, 279, 281, 282, 288, 289, 290, 291, 294, 303, 306, 307, 310, 311, 314, 335, 338, 340, 343, 345, 354, 355, 357, 358, 360, 363, 395, 396, 397, 402, 403, 404, 410, 411], "summary": {"covered_lines": 107, "num_statements": 125, "percent_covered": 85.6, "percent_covered_display": "86", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [26, 27, 46, 47, 56, 336, 341, 370, 375, 377, 378, 380, 381, 382, 383, 385, 392, 399], "excluded_lines": []}}}, "src/lyscripts/sample.py": {"executed_lines": [1, 19, 21, 22, 23, 25, 27, 29, 30, 31, 32, 34, 38, 40, 41, 42, 43, 44, 45, 46, 47, 49, 60, 63, 64, 66, 68, 69, 71, 73, 75, 78, 79, 81, 83, 84, 85, 86, 89, 90, 92, 93, 95, 97, 98, 100, 101, 103, 106, 107, 109, 110, 112, 114, 115, 117, 118, 120, 123, 126, 135, 140, 141, 142, 146, 147, 148, 150, 153, 162, 163, 175, 184, 185, 187, 190, 193, 209, 215, 217, 225, 257, 258, 260, 261, 262, 264, 265, 267, 268, 269, 270, 275, 277, 278, 280, 291, 297, 298, 300, 304, 305, 307, 311, 316, 322, 325, 327, 328, 334, 347, 348, 350, 351, 352, 359, 365, 366, 368, 385, 387, 391, 392, 393, 394, 395, 398, 400, 401, 402, 410, 419], "summary": {"covered_lines": 125, "num_statements": 136, "percent_covered": 91.91176470588235, "percent_covered_display": "92", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [35, 36, 74, 132, 172, 188, 301, 309, 313, 420, 421], "excluded_lines": [], "functions": {"CompletedItersColumn.__init__": {"executed_lines": [68, 69], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "CompletedItersColumn.render": {"executed_lines": [73, 75], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [74], "excluded_lines": []}, "ItersPerSecondColumn.render": {"executed_lines": [83, 84, 85, 86], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AcorTime.update": {"executed_lines": [97, 98], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AcorTime.relative_diff": {"executed_lines": [103], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NumAccepted.update": {"executed_lines": [114, 115], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NumAccepted.newly_accepted": {"executed_lines": [120], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "log_prob_fn": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [132], "excluded_lines": []}, "ensure_initial_state": {"executed_lines": [140, 141, 142, 146, 147, 148, 150], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ensure_history_table": {"executed_lines": [162, 163], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [172], "excluded_lines": []}, "update_history_table": {"executed_lines": [184, 185, 187, 190], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [188], "excluded_lines": []}, "is_converged": {"executed_lines": [209], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_get_columns": {"executed_lines": [217], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "run_sampling": {"executed_lines": [257, 258, 260, 261, 262, 264, 265, 267, 268, 269, 270, 275, 277, 278, 280, 291, 297, 298, 300], "summary": {"covered_lines": 19, "num_statements": 20, "percent_covered": 95.0, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [301], "excluded_lines": []}, "DummyPool.__enter__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [309], "excluded_lines": []}, "DummyPool.__exit__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [313], "excluded_lines": []}, "get_pool": {"executed_lines": [322], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "init_sampler": {"executed_lines": [327, 328, 334], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SampleCLI.cli_cmd": {"executed_lines": [385, 387, 391, 392, 393, 394, 395, 398, 400, 401, 402, 410], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 19, 21, 22, 23, 25, 27, 29, 30, 31, 32, 34, 38, 40, 41, 42, 43, 44, 45, 46, 47, 49, 60, 63, 64, 66, 71, 78, 79, 81, 89, 90, 92, 93, 95, 100, 101, 106, 107, 109, 110, 112, 117, 118, 123, 126, 135, 153, 175, 193, 215, 225, 304, 305, 307, 311, 316, 325, 347, 348, 350, 351, 352, 359, 365, 366, 368, 419], "summary": {"covered_lines": 61, "num_statements": 65, "percent_covered": 93.84615384615384, "percent_covered_display": "94", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [35, 36, 420, 421], "excluded_lines": []}}, "classes": {"CompletedItersColumn": {"executed_lines": [68, 69, 73, 75], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [74], "excluded_lines": []}, "ItersPerSecondColumn": {"executed_lines": [83, 84, 85, 86], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AcorTime": {"executed_lines": [97, 98, 103], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NumAccepted": {"executed_lines": [114, 115, 120], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyPool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [309, 313], "excluded_lines": []}, "SampleCLI": {"executed_lines": [385, 387, 391, 392, 393, 394, 395, 398, 400, 401, 402, 410], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 19, 21, 22, 23, 25, 27, 29, 30, 31, 32, 34, 38, 40, 41, 42, 43, 44, 45, 46, 47, 49, 60, 63, 64, 66, 71, 78, 79, 81, 89, 90, 92, 93, 95, 100, 101, 106, 107, 109, 110, 112, 117, 118, 123, 126, 135, 140, 141, 142, 146, 147, 148, 150, 153, 162, 163, 175, 184, 185, 187, 190, 193, 209, 215, 217, 225, 257, 258, 260, 261, 262, 264, 265, 267, 268, 269, 270, 275, 277, 278, 280, 291, 297, 298, 300, 304, 305, 307, 311, 316, 322, 325, 327, 328, 334, 347, 348, 350, 351, 352, 359, 365, 366, 368, 419], "summary": {"covered_lines": 99, "num_statements": 107, "percent_covered": 92.5233644859813, "percent_covered_display": "93", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [35, 36, 132, 172, 188, 301, 420, 421], "excluded_lines": []}}}, "src/lyscripts/schedule.py": {"executed_lines": [1, 13, 15, 16, 17, 19, 20, 23, 30, 38, 48, 55, 56, 58, 62, 66, 71, 83], "summary": {"covered_lines": 16, "num_statements": 29, "percent_covered": 55.172413793103445, "percent_covered_display": "55", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [25, 26, 27, 35, 44, 45, 73, 75, 76, 78, 80, 84, 85], "excluded_lines": [], "functions": {"geometric_schedule": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [25, 26, 27], "excluded_lines": []}, "linear_schedule": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [35], "excluded_lines": []}, "power_schedule": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [44, 45], "excluded_lines": []}, "ScheduleCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [73, 75, 76, 78, 80], "excluded_lines": []}, "": {"executed_lines": [1, 13, 15, 16, 17, 19, 20, 23, 30, 38, 48, 55, 56, 58, 62, 66, 71, 83], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [84, 85], "excluded_lines": []}}, "classes": {"ScheduleCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [73, 75, 76, 78, 80], "excluded_lines": []}, "": {"executed_lines": [1, 13, 15, 16, 17, 19, 20, 23, 30, 38, 48, 55, 56, 58, 62, 66, 71, 83], "summary": {"covered_lines": 16, "num_statements": 24, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [25, 26, 27, 35, 44, 45, 84, 85], "excluded_lines": []}}}, "src/lyscripts/schema.py": {"executed_lines": [1, 27, 29, 30, 32, 35, 36, 38, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 58, 64], "summary": {"covered_lines": 18, "num_statements": 21, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [60, 61, 65], "excluded_lines": [], "functions": {"main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [60, 61], "excluded_lines": []}, "": {"executed_lines": [1, 27, 29, 30, 32, 35, 36, 38, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 58, 64], "summary": {"covered_lines": 18, "num_statements": 19, "percent_covered": 94.73684210526316, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [65], "excluded_lines": []}}, "classes": {"SchemaSettings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 27, 29, 30, 32, 35, 36, 38, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 58, 64], "summary": {"covered_lines": 18, "num_statements": 21, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [60, 61, 65], "excluded_lines": []}}}, "src/lyscripts/utils.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 18, 21, 23, 24, 26, 27, 30, 33, 42, 43, 45, 46, 47, 48, 50, 53, 63, 65, 66, 67, 68, 70, 72, 75, 91, 93, 94, 95, 97, 98, 100, 102, 105, 115, 117, 118, 119, 120, 122, 124, 127, 137, 138, 139, 140, 143, 146, 151, 152, 154, 155, 156, 159, 160, 162, 163, 164, 165, 168, 169, 177, 178, 179, 180, 183, 184, 192, 193, 195, 199], "summary": {"covered_lines": 79, "num_statements": 84, "percent_covered": 94.04761904761905, "percent_covered_display": "94", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [25, 141, 142, 196, 197], "excluded_lines": [], "functions": {"binom_pmf": {"executed_lines": [23, 24, 26, 27, 30], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [25], "excluded_lines": []}, "get_dict_depth": {"executed_lines": [42, 43, 45, 46, 47, 48, 50], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "delete_private_keys": {"executed_lines": [63, 65, 66, 67, 68, 70, 72], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "flatten": {"executed_lines": [91, 93, 94, 95, 97, 98, 100, 102], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "unflatten": {"executed_lines": [115, 117, 118, 119, 120, 122, 124], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_modalities_subset": {"executed_lines": [137, 138, 139, 140, 143], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [141, 142], "excluded_lines": []}, "load_patient_data": {"executed_lines": [151, 152, 154, 155, 156], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "load_yaml_params": {"executed_lines": [162, 163, 164, 165], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "load_model_samples": {"executed_lines": [177, 178, 179, 180], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_hdf5_backend": {"executed_lines": [192, 193, 195, 199], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [196, 197], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 18, 21, 33, 53, 75, 105, 127, 146, 159, 160, 168, 169, 183, 184], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 18, 21, 23, 24, 26, 27, 30, 33, 42, 43, 45, 46, 47, 48, 50, 53, 63, 65, 66, 67, 68, 70, 72, 75, 91, 93, 94, 95, 97, 98, 100, 102, 105, 115, 117, 118, 119, 120, 122, 124, 127, 137, 138, 139, 140, 143, 146, 151, 152, 154, 155, 156, 159, 160, 162, 163, 164, 165, 168, 169, 177, 178, 179, 180, 183, 184, 192, 193, 195, 199], "summary": {"covered_lines": 79, "num_statements": 84, "percent_covered": 94.04761904761905, "percent_covered_display": "94", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [25, 141, 142, 196, 197], "excluded_lines": []}}}}, "totals": {"covered_lines": 1159, "num_statements": 1551, "percent_covered": 74.72598323662153, "percent_covered_display": "75", "missing_lines": 392, "excluded_lines": 0}}, "coverage_path": "."} \ No newline at end of file +{"coverage": 74.6987951807229, "raw_data": {"meta": {"format": 3, "version": "7.9.2", "timestamp": "2025-07-23T06:01:14.940919", "branch_coverage": false, "show_contexts": false}, "files": {"src/lyscripts/__init__.py": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 20, 21, 22, 23, 25, 26, 27, 28, 29, 33, 35, 38, 39, 41, 45, 50, 51, 52, 53, 55, 60, 75], "summary": {"covered_lines": 27, "num_statements": 34, "percent_covered": 79.41176470588235, "percent_covered_display": "79", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [57, 58, 66, 68, 69, 70, 72], "excluded_lines": [], "functions": {"LyscriptsCLI.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [57, 58], "excluded_lines": []}, "LyscriptsCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [66, 68, 69, 70, 72], "excluded_lines": []}, "": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 20, 21, 22, 23, 25, 26, 27, 28, 29, 33, 35, 38, 39, 41, 45, 50, 51, 52, 53, 55, 60, 75], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"LyscriptsCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [57, 58, 66, 68, 69, 70, 72], "excluded_lines": []}, "": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 20, 21, 22, 23, 25, 26, 27, 28, 29, 33, 35, 38, 39, 41, 45, 50, 51, 52, 53, 55, 60, 75], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/lyscripts/__main__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [3, 5, 6], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [3, 5, 6], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [3, 5, 6], "excluded_lines": []}}}, "src/lyscripts/_version.py": {"executed_lines": [4, 6, 7, 13, 15, 16, 17, 18, 20, 21], "summary": {"covered_lines": 10, "num_statements": 13, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [8, 9, 11], "excluded_lines": [], "functions": {"": {"executed_lines": [4, 6, 7, 13, 15, 16, 17, 18, 20, 21], "summary": {"covered_lines": 10, "num_statements": 13, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [8, 9, 11], "excluded_lines": []}}, "classes": {"": {"executed_lines": [4, 6, 7, 13, 15, 16, 17, 18, 20, 21], "summary": {"covered_lines": 10, "num_statements": 13, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [8, 9, 11], "excluded_lines": []}}}, "src/lyscripts/cli.py": {"executed_lines": [1, 11, 12, 14, 15, 16, 17, 18, 21, 35, 37, 44, 46, 49, 70], "summary": {"covered_lines": 14, "num_statements": 26, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [61, 62, 63, 64, 65, 67, 81, 82, 83, 84, 85, 86], "excluded_lines": [], "functions": {"assemble_main": {"executed_lines": [35, 46], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "assemble_main.main": {"executed_lines": [37, 44], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "somewhat_safely_get_loglevel": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [61, 62, 63, 64, 65, 67], "excluded_lines": []}, "configure_logging": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [81, 82, 83, 84, 85, 86], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 14, 15, 16, 17, 18, 21, 49, 70], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 11, 12, 14, 15, 16, 17, 18, 21, 35, 37, 44, 46, 49, 70], "summary": {"covered_lines": 14, "num_statements": 26, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [61, 62, 63, 64, 65, 67, 81, 82, 83, 84, 85, 86], "excluded_lines": []}}}, "src/lyscripts/compute/__init__.py": {"executed_lines": [1, 6, 8, 11, 12, 14, 15, 16, 17, 19], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [21], "excluded_lines": [], "functions": {"ComputeCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [21], "excluded_lines": []}, "": {"executed_lines": [1, 6, 8, 11, 12, 14, 15, 16, 17, 19], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ComputeCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [21], "excluded_lines": []}, "": {"executed_lines": [1, 6, 8, 11, 12, 14, 15, 16, 17, 19], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/lyscripts/compute/__main__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [3, 4, 6, 7, 8], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [3, 4, 6, 7, 8], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [3, 4, 6, 7, 8], "excluded_lines": []}}}, "src/lyscripts/compute/posteriors.py": {"executed_lines": [1, 9, 11, 12, 13, 14, 15, 17, 18, 19, 20, 29, 32, 51, 52, 53, 54, 55, 57, 58, 60, 66, 75, 78, 79, 81, 87, 91, 140], "summary": {"covered_lines": 27, "num_statements": 46, "percent_covered": 58.69565217391305, "percent_covered_display": "59", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [97, 99, 102, 104, 105, 106, 107, 109, 110, 111, 113, 122, 123, 125, 135, 136, 137, 141, 142], "excluded_lines": [], "functions": {"compute_posteriors": {"executed_lines": [51, 52, 53, 54, 55, 57, 58, 60, 66, 75], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PosteriorsCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [97, 99, 102, 104, 105, 106, 107, 109, 110, 111, 113, 122, 123, 125, 135, 136, 137], "excluded_lines": []}, "": {"executed_lines": [1, 9, 11, 12, 13, 14, 15, 17, 18, 19, 20, 29, 32, 78, 79, 81, 87, 91, 140], "summary": {"covered_lines": 17, "num_statements": 19, "percent_covered": 89.47368421052632, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [141, 142], "excluded_lines": []}}, "classes": {"PosteriorsCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [97, 99, 102, 104, 105, 106, 107, 109, 110, 111, 113, 122, 123, 125, 135, 136, 137], "excluded_lines": []}, "": {"executed_lines": [1, 9, 11, 12, 13, 14, 15, 17, 18, 19, 20, 29, 32, 51, 52, 53, 54, 55, 57, 58, 60, 66, 75, 78, 79, 81, 87, 91, 140], "summary": {"covered_lines": 27, "num_statements": 29, "percent_covered": 93.10344827586206, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [141, 142], "excluded_lines": []}}}, "src/lyscripts/compute/prevalences.py": {"executed_lines": [1, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 29, 41, 44, 55, 56, 58, 63, 64, 65, 67, 73, 74, 79, 80, 82, 88, 102, 104, 107, 109, 110, 111, 112, 113, 114, 115, 118, 142, 143, 144, 146, 147, 148, 150, 157, 163, 164, 166, 172, 175, 177, 179, 180, 183, 185, 186, 187, 188, 190, 191, 192, 194, 203, 204, 206, 216, 221, 222, 223, 224, 233], "summary": {"covered_lines": 75, "num_statements": 82, "percent_covered": 91.46341463414635, "percent_covered_display": "91", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [59, 60, 61, 95, 100, 234, 235], "excluded_lines": [], "functions": {"compute_prevalences": {"executed_lines": [55, 56, 58, 63, 64, 65, 67, 73, 74, 79, 80, 82, 88, 102, 104], "summary": {"covered_lines": 15, "num_statements": 20, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [59, 60, 61, 95, 100], "excluded_lines": []}, "generate_query_from_diagnosis": {"executed_lines": [109, 110, 111, 112, 113, 114, 115], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "observe_prevalence": {"executed_lines": [142, 143, 144, 146, 147, 148, 150, 157], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PrevalencesCLI.cli_cmd": {"executed_lines": [179, 180, 183, 185, 186, 187, 188, 190, 191, 192, 194, 203, 204, 206, 216, 221, 222, 223, 224], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 29, 41, 44, 107, 118, 163, 164, 166, 172, 175, 177, 233], "summary": {"covered_lines": 26, "num_statements": 28, "percent_covered": 92.85714285714286, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [234, 235], "excluded_lines": []}}, "classes": {"PrevalencesCLI": {"executed_lines": [179, 180, 183, 185, 186, 187, 188, 190, 191, 192, 194, 203, 204, 206, 216, 221, 222, 223, 224], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 29, 41, 44, 55, 56, 58, 63, 64, 65, 67, 73, 74, 79, 80, 82, 88, 102, 104, 107, 109, 110, 111, 112, 113, 114, 115, 118, 142, 143, 144, 146, 147, 148, 150, 157, 163, 164, 166, 172, 175, 177, 233], "summary": {"covered_lines": 56, "num_statements": 63, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [59, 60, 61, 95, 100, 234, 235], "excluded_lines": []}}}, "src/lyscripts/compute/priors.py": {"executed_lines": [1, 7, 9, 10, 11, 12, 14, 15, 16, 23, 26, 42, 43, 44, 46, 52, 53, 60, 63, 64, 66, 68, 84, 85, 86, 88, 89, 90, 92, 93, 94, 96, 105, 106, 109], "summary": {"covered_lines": 33, "num_statements": 35, "percent_covered": 94.28571428571429, "percent_covered_display": "94", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [110, 111], "excluded_lines": [], "functions": {"compute_priors": {"executed_lines": [42, 43, 44, 46, 52, 53, 60], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PriorsCLI.cli_cmd": {"executed_lines": [84, 85, 86, 88, 89, 90, 92, 93, 94, 96, 105, 106], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 7, 9, 10, 11, 12, 14, 15, 16, 23, 26, 63, 64, 66, 68, 109], "summary": {"covered_lines": 14, "num_statements": 16, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [110, 111], "excluded_lines": []}}, "classes": {"PriorsCLI": {"executed_lines": [84, 85, 86, 88, 89, 90, 92, 93, 94, 96, 105, 106], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 7, 9, 10, 11, 12, 14, 15, 16, 23, 26, 42, 43, 44, 46, 52, 53, 60, 63, 64, 66, 68, 109], "summary": {"covered_lines": 21, "num_statements": 23, "percent_covered": 91.30434782608695, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [110, 111], "excluded_lines": []}}}, "src/lyscripts/compute/risks.py": {"executed_lines": [1, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 29, 32, 68, 69, 71, 77, 79, 138], "summary": {"covered_lines": 18, "num_statements": 51, "percent_covered": 35.294117647058826, "percent_covered_display": "35", "missing_lines": 33, "excluded_lines": 0}, "missing_lines": [47, 48, 49, 50, 52, 53, 55, 61, 65, 81, 82, 85, 87, 88, 89, 90, 91, 93, 94, 95, 97, 106, 107, 109, 119, 120, 122, 132, 133, 134, 135, 139, 140], "excluded_lines": [], "functions": {"compute_risks": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [47, 48, 49, 50, 52, 53, 55, 61, 65], "excluded_lines": []}, "RisksCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [81, 82, 85, 87, 88, 89, 90, 91, 93, 94, 95, 97, 106, 107, 109, 119, 120, 122, 132, 133, 134, 135], "excluded_lines": []}, "": {"executed_lines": [1, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 29, 32, 68, 69, 71, 77, 79, 138], "summary": {"covered_lines": 18, "num_statements": 20, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [139, 140], "excluded_lines": []}}, "classes": {"RisksCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [81, 82, 85, 87, 88, 89, 90, 91, 93, 94, 95, 97, 106, 107, 109, 119, 120, 122, 132, 133, 134, 135], "excluded_lines": []}, "": {"executed_lines": [1, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 29, 32, 68, 69, 71, 77, 79, 138], "summary": {"covered_lines": 18, "num_statements": 29, "percent_covered": 62.06896551724138, "percent_covered_display": "62", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [47, 48, 49, 50, 52, 53, 55, 61, 65, 139, 140], "excluded_lines": []}}}, "src/lyscripts/compute/utils.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 14, 24, 25, 27, 28, 29, 36, 40, 44, 47, 49, 55, 57, 58, 59, 60, 62, 63, 66, 68, 69, 70, 71, 72, 73, 74, 77, 92, 94, 97, 98, 99, 101, 104, 106, 107, 108, 111, 112, 115, 116, 118, 121, 128, 145, 148, 149, 151, 153, 155, 156, 158, 159, 161, 163, 165, 166, 168, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 187, 189, 191, 194, 210, 211, 212, 213, 214, 215, 216, 217, 219, 222, 239, 242, 243, 244, 246, 247, 248, 249, 252, 254, 257, 259, 260, 261, 263, 264, 265, 266, 267, 269, 271, 272, 273, 275, 276], "summary": {"covered_lines": 114, "num_statements": 120, "percent_covered": 95.0, "percent_covered_display": "95", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [95, 146, 177, 188, 240, 250], "excluded_lines": [], "functions": {"is_hdf5_compatible": {"executed_lines": [49], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "to_hdf5_attrs": {"executed_lines": [57, 58, 59, 60, 62, 63], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "from_hdf5_attrs": {"executed_lines": [68, 69, 70, 71, 72, 73, 74], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "extract_modalities": {"executed_lines": [92, 94, 97, 98, 99, 101], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [95], "excluded_lines": []}, "ensure_parent_dir": {"executed_lines": [106, 107, 108], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "HDF5FileStorage._get_dataset": {"executed_lines": [145, 148, 149], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [146], "excluded_lines": []}, "HDF5FileStorage.load": {"executed_lines": [153, 155, 156, 158, 159], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "HDF5FileStorage.get_attrs": {"executed_lines": [163, 165, 166, 168, 169], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "HDF5FileStorage.save": {"executed_lines": [173, 175, 176, 178, 180], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [177], "excluded_lines": []}, "HDF5FileStorage.set_attrs": {"executed_lines": [184, 186, 187, 189, 191], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [188], "excluded_lines": []}, "reduce_pattern": {"executed_lines": [210, 211, 212, 213, 214, 215, 216, 217, 219], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "complete_pattern": {"executed_lines": [239, 242, 243, 244, 246, 247, 248, 249, 252, 254], "summary": {"covered_lines": 10, "num_statements": 12, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [240, 250], "excluded_lines": []}, "get_cached": {"executed_lines": [259, 260, 261, 263, 264, 275, 276], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_cached.log_cache_info_wrapper": {"executed_lines": [265, 266, 267, 269, 271, 272, 273], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 14, 24, 25, 27, 28, 29, 36, 40, 44, 47, 55, 66, 77, 104, 111, 112, 115, 116, 118, 121, 128, 151, 161, 171, 182, 194, 222, 257], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"BaseComputeCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "HDF5FileStorage": {"executed_lines": [145, 148, 149, 153, 155, 156, 158, 159, 163, 165, 166, 168, 169, 173, 175, 176, 178, 180, 184, 186, 187, 189, 191], "summary": {"covered_lines": 23, "num_statements": 26, "percent_covered": 88.46153846153847, "percent_covered_display": "88", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [146, 177, 188], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 14, 24, 25, 27, 28, 29, 36, 40, 44, 47, 49, 55, 57, 58, 59, 60, 62, 63, 66, 68, 69, 70, 71, 72, 73, 74, 77, 92, 94, 97, 98, 99, 101, 104, 106, 107, 108, 111, 112, 115, 116, 118, 121, 128, 151, 161, 171, 182, 194, 210, 211, 212, 213, 214, 215, 216, 217, 219, 222, 239, 242, 243, 244, 246, 247, 248, 249, 252, 254, 257, 259, 260, 261, 263, 264, 265, 266, 267, 269, 271, 272, 273, 275, 276], "summary": {"covered_lines": 91, "num_statements": 94, "percent_covered": 96.80851063829788, "percent_covered_display": "97", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [95, 240, 250], "excluded_lines": []}}}, "src/lyscripts/configs.py": {"executed_lines": [1, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 39, 44, 46, 48, 51, 56, 57, 59, 63, 69, 70, 72, 78, 82, 87, 89, 92, 94, 96, 102, 104, 107, 108, 110, 115, 120, 128, 129, 131, 135, 139, 145, 146, 148, 153, 159, 161, 162, 164, 167, 168, 170, 171, 176, 177, 179, 182, 186, 187, 189, 190, 202, 204, 205, 206, 208, 209, 211, 214, 216, 219, 220, 222, 225, 226, 228, 232, 236, 240, 244, 253, 258, 259, 261, 270, 273, 275, 276, 280, 281, 282, 283, 285, 288, 296, 298, 299, 306, 307, 316, 321, 325, 332, 336, 341, 343, 348, 349, 350, 355, 357, 359, 360, 362, 363, 364, 366, 367, 368, 370, 372, 379, 380, 381, 387, 390, 391, 393, 396, 400, 404, 412, 416, 420, 424, 431, 435, 439, 443, 451, 457, 464, 466, 467, 469, 470, 475, 476, 478, 482, 487, 491, 495, 496, 498, 500, 501, 503, 505, 511, 513, 519, 521, 522, 523, 524, 525, 526, 529, 550, 551, 553, 554, 555, 561, 562, 565, 572, 573, 574, 576, 578, 579, 580, 581, 582, 583, 587, 588, 589, 590, 592, 594, 595, 598, 604, 605, 606, 608, 609, 610, 612, 613, 616, 640, 643, 644, 657, 672, 673, 675, 677, 678, 679, 684, 686, 688, 692, 693, 699, 701, 703, 713, 714, 716, 718, 728, 729, 738, 743, 744], "summary": {"covered_lines": 228, "num_statements": 255, "percent_covered": 89.41176470588235, "percent_covered_display": "89", "missing_lines": 27, "excluded_lines": 0}, "missing_lines": [90, 122, 165, 173, 217, 271, 277, 278, 286, 472, 506, 507, 509, 514, 585, 624, 625, 627, 628, 629, 631, 632, 633, 635, 636, 637, 680], "excluded_lines": [], "functions": {"DataConfig.load": {"executed_lines": [89, 92], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [90], "excluded_lines": []}, "DataConfig.get_load_kwargs": {"executed_lines": [96], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "check_pattern": {"executed_lines": [104], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DiagnosisConfig.to_involvement": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [122], "excluded_lines": []}, "retrieve_graph_representation": {"executed_lines": [161, 162, 164, 167, 168, 170, 171], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [165, 173], "excluded_lines": []}, "GraphConfig.from_model": {"executed_lines": [189, 190], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "has_model_symbol": {"executed_lines": [204, 205, 206, 208, 209, 211], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_symmetry_kwargs": {"executed_lines": [216, 219, 220, 222], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [217], "excluded_lines": []}, "ModelConfig.from_model": {"executed_lines": [261, 270, 273, 275, 276, 280, 281, 282, 283, 285, 288], "summary": {"covered_lines": 11, "num_statements": 15, "percent_covered": 73.33333333333333, "percent_covered_display": "73", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [271, 277, 278, 286], "excluded_lines": []}, "modalityconfig_from_model": {"executed_lines": [298, 299], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DeprecatedModelConfig.model_post_init": {"executed_lines": [343, 348, 349, 350, 355], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DeprecatedModelConfig.translate": {"executed_lines": [359, 360, 362, 363, 364, 366, 367, 368, 370, 372, 379, 380, 381, 387], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SamplingConfig.load": {"executed_lines": [457], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "map_to_optional_bool": {"executed_lines": [466, 467, 469, 470], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [472], "excluded_lines": []}, "ScenarioConfig.model_post_init": {"executed_lines": [500, 501], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ScenarioConfig.interpolate": {"executed_lines": [505], "summary": {"covered_lines": 1, "num_statements": 4, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [506, 507, 509], "excluded_lines": []}, "ScenarioConfig.normalize": {"executed_lines": [513], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [514], "excluded_lines": []}, "_construct_model_from_external": {"executed_lines": [521, 522, 523, 524, 525, 526], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "construct_model": {"executed_lines": [550, 551, 553, 554, 555, 561, 562], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "add_distributions": {"executed_lines": [572, 573, 574, 576, 578, 579, 580, 581, 582, 583, 587, 588, 589, 590, 592, 594, 595], "summary": {"covered_lines": 17, "num_statements": 18, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [585], "excluded_lines": []}, "add_modalities": {"executed_lines": [604, 605, 606, 608, 609, 610, 612, 613], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "add_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [624, 625, 627, 628, 629, 631, 632, 633, 635, 636, 637], "excluded_lines": []}, "DynamicYamlConfigSettingsSource.__init__": {"executed_lines": [672, 673], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DynamicYamlConfigSettingsSource._read_file": {"executed_lines": [677, 678, 679, 684], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [680], "excluded_lines": []}, "DynamicYamlConfigSettingsSource.__call__": {"executed_lines": [688, 692, 693, 699], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DynamicYamlConfigSettingsSource.__repr__": {"executed_lines": [703], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BaseCLI.settings_customise_sources": {"executed_lines": [738, 743, 744], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 39, 44, 46, 48, 51, 56, 57, 59, 63, 69, 70, 72, 78, 82, 87, 94, 102, 107, 108, 110, 115, 120, 128, 129, 131, 135, 139, 145, 146, 148, 153, 159, 176, 177, 179, 182, 186, 187, 202, 214, 225, 226, 228, 232, 236, 240, 244, 253, 258, 259, 296, 306, 307, 316, 321, 325, 332, 336, 341, 357, 390, 391, 393, 396, 400, 404, 412, 416, 420, 424, 431, 435, 439, 443, 451, 464, 475, 476, 478, 482, 487, 491, 495, 496, 498, 503, 511, 519, 529, 565, 598, 616, 640, 643, 644, 657, 675, 686, 701, 713, 714, 716, 718, 728, 729], "summary": {"covered_lines": 112, "num_statements": 112, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"CrossValidationConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DataConfig": {"executed_lines": [89, 92, 96], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [90], "excluded_lines": []}, "DiagnosisConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [122], "excluded_lines": []}, "DistributionConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "InvolvementConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "GraphConfig": {"executed_lines": [189, 190], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ModelConfig": {"executed_lines": [261, 270, 273, 275, 276, 280, 281, 282, 283, 285, 288], "summary": {"covered_lines": 11, "num_statements": 15, "percent_covered": 73.33333333333333, "percent_covered_display": "73", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [271, 277, 278, 286], "excluded_lines": []}, "DeprecatedModelConfig": {"executed_lines": [343, 348, 349, 350, 355, 359, 360, 362, 363, 364, 366, 367, 368, 370, 372, 379, 380, 381, 387], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SamplingConfig": {"executed_lines": [457], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ScenarioConfig": {"executed_lines": [500, 501, 505, 513], "summary": {"covered_lines": 4, "num_statements": 8, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [506, 507, 509, 514], "excluded_lines": []}, "DynamicYamlConfigSettingsSource": {"executed_lines": [672, 673, 677, 678, 679, 684, 688, 692, 693, 699, 703], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [680], "excluded_lines": []}, "BaseCLI": {"executed_lines": [738, 743, 744], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 39, 44, 46, 48, 51, 56, 57, 59, 63, 69, 70, 72, 78, 82, 87, 94, 102, 104, 107, 108, 110, 115, 120, 128, 129, 131, 135, 139, 145, 146, 148, 153, 159, 161, 162, 164, 167, 168, 170, 171, 176, 177, 179, 182, 186, 187, 202, 204, 205, 206, 208, 209, 211, 214, 216, 219, 220, 222, 225, 226, 228, 232, 236, 240, 244, 253, 258, 259, 296, 298, 299, 306, 307, 316, 321, 325, 332, 336, 341, 357, 390, 391, 393, 396, 400, 404, 412, 416, 420, 424, 431, 435, 439, 443, 451, 464, 466, 467, 469, 470, 475, 476, 478, 482, 487, 491, 495, 496, 498, 503, 511, 519, 521, 522, 523, 524, 525, 526, 529, 550, 551, 553, 554, 555, 561, 562, 565, 572, 573, 574, 576, 578, 579, 580, 581, 582, 583, 587, 588, 589, 590, 592, 594, 595, 598, 604, 605, 606, 608, 609, 610, 612, 613, 616, 640, 643, 644, 657, 675, 686, 701, 713, 714, 716, 718, 728, 729], "summary": {"covered_lines": 174, "num_statements": 190, "percent_covered": 91.57894736842105, "percent_covered_display": "92", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [165, 173, 217, 472, 585, 624, 625, 627, 628, 629, 631, 632, 633, 635, 636, 637], "excluded_lines": []}}}, "src/lyscripts/data/__init__.py": {"executed_lines": [1, 17, 19, 29, 32, 33, 35, 36, 37, 38, 39, 40, 41, 43], "summary": {"covered_lines": 12, "num_statements": 13, "percent_covered": 92.3076923076923, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [45], "excluded_lines": [], "functions": {"DataCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [45], "excluded_lines": []}, "": {"executed_lines": [1, 17, 19, 29, 32, 33, 35, 36, 37, 38, 39, 40, 41, 43], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DataCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [45], "excluded_lines": []}, "": {"executed_lines": [1, 17, 19, 29, 32, 33, 35, 36, 37, 38, 39, 40, 41, 43], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/lyscripts/data/__main__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 7, 10, 13, 15, 20, 21, 25, 26, 27, 28, 29, 31, 32, 35, 36], "excluded_lines": [], "functions": {"main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [15, 20, 21, 25, 26, 27, 28, 29, 31, 32], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 7, 10, 13, 35, 36], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 7, 10, 13, 15, 20, 21, 25, 26, 27, 28, 29, 31, 32, 35, 36], "excluded_lines": []}}}, "src/lyscripts/data/enhance.py": {"executed_lines": [1, 7, 9, 10, 11, 13, 14, 15, 18, 19, 21, 22, 23, 24, 25, 30, 32, 61], "summary": {"covered_lines": 16, "num_statements": 24, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [39, 41, 42, 44, 49, 58, 62, 63], "excluded_lines": [], "functions": {"EnhanceCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [39, 41, 42, 44, 49, 58], "excluded_lines": []}, "": {"executed_lines": [1, 7, 9, 10, 11, 13, 14, 15, 18, 19, 21, 22, 23, 24, 25, 30, 32, 61], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [62, 63], "excluded_lines": []}}, "classes": {"EnhanceCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [39, 41, 42, 44, 49, 58], "excluded_lines": []}, "": {"executed_lines": [1, 7, 9, 10, 11, 13, 14, 15, 18, 19, 21, 22, 23, 24, 25, 30, 32, 61], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [62, 63], "excluded_lines": []}}}, "src/lyscripts/data/fetch.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 10, 11, 14, 15, 17, 24, 31, 38, 40, 55], "summary": {"covered_lines": 14, "num_statements": 21, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [42, 43, 45, 51, 52, 56, 57], "excluded_lines": [], "functions": {"FetchCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [42, 43, 45, 51, 52], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 10, 11, 14, 15, 17, 24, 31, 38, 40, 55], "summary": {"covered_lines": 14, "num_statements": 16, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [56, 57], "excluded_lines": []}}, "classes": {"FetchCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [42, 43, 45, 51, 52], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 10, 11, 14, 15, 17, 24, 31, 38, 40, 55], "summary": {"covered_lines": 14, "num_statements": 16, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [56, 57], "excluded_lines": []}}}, "src/lyscripts/data/filter.py": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 15, 16, 17, 20, 21, 23, 24, 28, 35, 38, 39, 41, 68, 97], "summary": {"covered_lines": 19, "num_statements": 49, "percent_covered": 38.775510204081634, "percent_covered_display": "39", "missing_lines": 30, "excluded_lines": 0}, "missing_lines": [43, 44, 45, 46, 47, 49, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 66, 76, 78, 79, 84, 85, 87, 88, 89, 91, 92, 94, 98, 99], "excluded_lines": [], "functions": {"FilterCLI.model_post_init": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [43, 44, 45, 46, 47, 49, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 66], "excluded_lines": []}, "FilterCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [76, 78, 79, 84, 85, 87, 88, 89, 91, 92, 94], "excluded_lines": []}, "": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 15, 16, 17, 20, 21, 23, 24, 28, 35, 38, 39, 41, 68, 97], "summary": {"covered_lines": 19, "num_statements": 21, "percent_covered": 90.47619047619048, "percent_covered_display": "90", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [98, 99], "excluded_lines": []}}, "classes": {"FilterCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 28, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [43, 44, 45, 46, 47, 49, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 66, 76, 78, 79, 84, 85, 87, 88, 89, 91, 92, 94], "excluded_lines": []}, "": {"executed_lines": [1, 7, 8, 10, 11, 12, 13, 15, 16, 17, 20, 21, 23, 24, 28, 35, 38, 39, 41, 68, 97], "summary": {"covered_lines": 19, "num_statements": 21, "percent_covered": 90.47619047619048, "percent_covered_display": "90", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [98, 99], "excluded_lines": []}}}, "src/lyscripts/data/generate.py": {"executed_lines": [1, 11, 12, 13, 14, 16, 17, 26, 29, 30, 32, 33, 34, 41, 47, 48, 49, 50, 51, 53, 55, 56, 57, 60, 62, 65, 67, 76, 78, 79, 80, 81, 82, 84, 89, 91, 94], "summary": {"covered_lines": 35, "num_statements": 39, "percent_covered": 89.74358974358974, "percent_covered_display": "90", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [58, 63, 95, 96], "excluded_lines": [], "functions": {"GenerateCLI.model_post_init": {"executed_lines": [55, 56, 57, 60, 62, 65], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [58, 63], "excluded_lines": []}, "GenerateCLI.cli_cmd": {"executed_lines": [76, 78, 79, 80, 81, 82, 84, 89, 91], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 13, 14, 16, 17, 26, 29, 30, 32, 33, 34, 41, 47, 48, 49, 50, 51, 53, 67, 94], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [95, 96], "excluded_lines": []}}, "classes": {"GenerateCLI": {"executed_lines": [55, 56, 57, 60, 62, 65, 76, 78, 79, 80, 81, 82, 84, 89, 91], "summary": {"covered_lines": 15, "num_statements": 17, "percent_covered": 88.23529411764706, "percent_covered_display": "88", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [58, 63], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 13, 14, 16, 17, 26, 29, 30, 32, 33, 34, 41, 47, 48, 49, 50, 51, 53, 67, 94], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [95, 96], "excluded_lines": []}}}, "src/lyscripts/data/join.py": {"executed_lines": [1, 3, 5, 6, 8, 9, 10, 13, 14, 16, 17, 19, 76], "summary": {"covered_lines": 11, "num_statements": 20, "percent_covered": 55.0, "percent_covered_display": "55", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [60, 62, 63, 64, 65, 67, 73, 77, 78], "excluded_lines": [], "functions": {"JoinCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [60, 62, 63, 64, 65, 67, 73], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 8, 9, 10, 13, 14, 16, 17, 19, 76], "summary": {"covered_lines": 11, "num_statements": 13, "percent_covered": 84.61538461538461, "percent_covered_display": "85", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [77, 78], "excluded_lines": []}}, "classes": {"JoinCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [60, 62, 63, 64, 65, 67, 73], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 8, 9, 10, 13, 14, 16, 17, 19, 76], "summary": {"covered_lines": 11, "num_statements": 13, "percent_covered": 84.61538461538461, "percent_covered_display": "85", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [77, 78], "excluded_lines": []}}}, "src/lyscripts/data/lyproxify.py": {"executed_lines": [1, 10, 11, 12, 13, 15, 16, 17, 18, 19, 21, 22, 23, 24, 26, 29, 37, 49, 50, 52, 53, 57, 67, 74, 78, 80, 122, 123, 126, 145, 162, 163, 164, 165, 167, 169, 176, 199, 200, 201, 202, 203, 204, 205, 206, 208, 210, 213, 285, 310, 327, 328, 330, 331, 332, 334, 335, 336, 339], "summary": {"covered_lines": 56, "num_statements": 123, "percent_covered": 45.52845528455285, "percent_covered_display": "46", "missing_lines": 67, "excluded_lines": 0}, "missing_lines": [31, 32, 34, 39, 40, 41, 43, 44, 46, 90, 92, 96, 102, 103, 104, 105, 106, 108, 109, 110, 111, 113, 114, 116, 117, 119, 132, 134, 135, 136, 141, 142, 173, 250, 252, 253, 255, 256, 258, 259, 260, 261, 262, 263, 264, 265, 267, 268, 271, 272, 276, 281, 282, 293, 294, 295, 297, 298, 299, 300, 302, 303, 304, 306, 307, 340, 341], "excluded_lines": [], "functions": {"ensure_python_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [31, 32, 34], "excluded_lines": []}, "ensure_column_map": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [39, 40, 41, 43, 44, 46], "excluded_lines": []}, "LyproxifyCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [90, 92, 96, 102, 103, 104, 105, 106, 108, 109, 110, 111, 113, 114, 116, 117, 119], "excluded_lines": []}, "clean_header": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [132, 134, 135, 136, 141, 142], "excluded_lines": []}, "get_instruction_depth": {"executed_lines": [162, 163, 164, 165, 167, 169], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [173], "excluded_lines": []}, "generate_markdown_docs": {"executed_lines": [199, 200, 201, 202, 203, 204, 205, 206, 208, 210], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "transform_to_lyprox": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [250, 252, 253, 255, 256, 258, 259, 260, 261, 262, 263, 264, 265, 267, 268, 271, 272, 276, 281, 282], "excluded_lines": []}, "leftright_to_ipsicontra": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [293, 294, 295, 297, 298, 299, 300, 302, 303, 304, 306, 307], "excluded_lines": []}, "exclude_patients": {"executed_lines": [327, 328, 330, 331, 332, 334, 335, 336], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 10, 11, 12, 13, 15, 16, 17, 18, 19, 21, 22, 23, 24, 26, 29, 37, 49, 50, 52, 53, 57, 67, 74, 78, 80, 122, 123, 126, 145, 176, 213, 285, 310, 339], "summary": {"covered_lines": 32, "num_statements": 34, "percent_covered": 94.11764705882354, "percent_covered_display": "94", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [340, 341], "excluded_lines": []}}, "classes": {"LyproxifyCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [90, 92, 96, 102, 103, 104, 105, 106, 108, 109, 110, 111, 113, 114, 116, 117, 119], "excluded_lines": []}, "ParsingError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 10, 11, 12, 13, 15, 16, 17, 18, 19, 21, 22, 23, 24, 26, 29, 37, 49, 50, 52, 53, 57, 67, 74, 78, 80, 122, 123, 126, 145, 162, 163, 164, 165, 167, 169, 176, 199, 200, 201, 202, 203, 204, 205, 206, 208, 210, 213, 285, 310, 327, 328, 330, 331, 332, 334, 335, 336, 339], "summary": {"covered_lines": 56, "num_statements": 106, "percent_covered": 52.83018867924528, "percent_covered_display": "53", "missing_lines": 50, "excluded_lines": 0}, "missing_lines": [31, 32, 34, 39, 40, 41, 43, 44, 46, 132, 134, 135, 136, 141, 142, 173, 250, 252, 253, 255, 256, 258, 259, 260, 261, 262, 263, 264, 265, 267, 268, 271, 272, 276, 281, 282, 293, 294, 295, 297, 298, 299, 300, 302, 303, 304, 306, 307, 340, 341], "excluded_lines": []}}}, "src/lyscripts/data/split.py": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 18, 19, 21, 22, 23, 25, 71], "summary": {"covered_lines": 16, "num_statements": 30, "percent_covered": 53.333333333333336, "percent_covered_display": "53", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [33, 35, 36, 38, 40, 46, 50, 51, 54, 59, 61, 65, 72, 73], "excluded_lines": [], "functions": {"SplitCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [33, 35, 36, 38, 40, 46, 50, 51, 54, 59, 61, 65], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 18, 19, 21, 22, 23, 25, 71], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [72, 73], "excluded_lines": []}}, "classes": {"SplitCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [33, 35, 36, 38, 40, 46, 50, 51, 54, 59, 61, 65], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 18, 19, 21, 22, 23, 25, 71], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [72, 73], "excluded_lines": []}}}, "src/lyscripts/data/utils.py": {"executed_lines": [1, 3, 5, 6, 8, 11, 12, 14, 15, 16], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"save_table_to_csv": {"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}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 8, 11, 12], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 8, 11, 12, 14, 15, 16], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/lyscripts/decorators.py": {"executed_lines": [1, 8, 9, 10, 11, 12, 13, 16, 18, 19, 20, 23, 30, 33, 34, 36, 37, 38, 39, 41, 42, 51, 57, 59, 62, 65, 66, 68, 69, 72, 74, 77, 80, 81, 83, 84, 86, 88], "summary": {"covered_lines": 37, "num_statements": 41, "percent_covered": 90.2439024390244, "percent_covered_display": "90", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [53, 54, 55, 70], "excluded_lines": [], "functions": {"assemble_signature": {"executed_lines": [18, 19, 20], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "log_state": {"executed_lines": [30, 59], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "log_state.log_decorator": {"executed_lines": [33, 34, 57], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "log_state.log_decorator.wrapper": {"executed_lines": [36, 37, 38, 39, 41, 42, 51], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [53, 54, 55], "excluded_lines": []}, "check_input_file_exists": {"executed_lines": [65, 66, 74], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "check_input_file_exists.inner": {"executed_lines": [68, 69, 72], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [70], "excluded_lines": []}, "check_output_dir_exists": {"executed_lines": [80, 81, 88], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "check_output_dir_exists.inner": {"executed_lines": [83, 84, 86], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 8, 9, 10, 11, 12, 13, 16, 23, 62, 77], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 8, 9, 10, 11, 12, 13, 16, 18, 19, 20, 23, 30, 33, 34, 36, 37, 38, 39, 41, 42, 51, 57, 59, 62, 65, 66, 68, 69, 72, 74, 77, 80, 81, 83, 84, 86, 88], "summary": {"covered_lines": 37, "num_statements": 41, "percent_covered": 90.2439024390244, "percent_covered_display": "90", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [53, 54, 55, 70], "excluded_lines": []}}}, "src/lyscripts/evaluate.py": {"executed_lines": [1, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 21, 24, 38, 73, 90, 112, 144, 207], "summary": {"covered_lines": 18, "num_statements": 75, "percent_covered": 24.0, "percent_covered_display": "24", "missing_lines": 57, "excluded_lines": 0}, "missing_lines": [29, 35, 43, 48, 50, 57, 63, 70, 87, 104, 105, 106, 107, 108, 109, 120, 121, 123, 124, 129, 130, 131, 133, 134, 135, 137, 138, 139, 141, 146, 148, 149, 150, 151, 152, 155, 156, 163, 169, 171, 181, 182, 185, 186, 187, 190, 191, 193, 198, 199, 201, 202, 204, 208, 209, 211, 212], "excluded_lines": [], "functions": {"_add_parser": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [29, 35], "excluded_lines": []}, "_add_arguments": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [43, 48, 50, 57, 63, 70], "excluded_lines": []}, "comp_bic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [87], "excluded_lines": []}, "compute_evidence": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [104, 105, 106, 107, 108, 109], "excluded_lines": []}, "compute_ti_results": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [120, 121, 123, 124, 129, 130, 131, 133, 134, 135, 137, 138, 139, 141], "excluded_lines": []}, "main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 0}, "missing_lines": [146, 148, 149, 150, 151, 152, 155, 156, 163, 169, 171, 181, 182, 185, 186, 187, 190, 191, 193, 198, 199, 201, 202, 204], "excluded_lines": []}, "": {"executed_lines": [1, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 21, 24, 38, 73, 90, 112, 144, 207], "summary": {"covered_lines": 18, "num_statements": 22, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [208, 209, 211, 212], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 21, 24, 38, 73, 90, 112, 144, 207], "summary": {"covered_lines": 18, "num_statements": 75, "percent_covered": 24.0, "percent_covered_display": "24", "missing_lines": 57, "excluded_lines": 0}, "missing_lines": [29, 35, 43, 48, 50, 57, 63, 70, 87, 104, 105, 106, 107, 108, 109, 120, 121, 123, 124, 129, 130, 131, 133, 134, 135, 137, 138, 139, 141, 146, 148, 149, 150, 151, 152, 155, 156, 163, 169, 171, 181, 182, 185, 186, 187, 190, 191, 193, 198, 199, 201, 202, 204, 208, 209, 211, 212], "excluded_lines": []}}}, "src/lyscripts/plots.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 25, 30, 37, 38, 41, 50, 59, 61, 64, 66, 69, 74, 75, 76, 77, 78, 81, 84, 85, 87, 88, 89, 91, 92, 96, 97, 101, 102, 106, 109, 110, 112, 115, 116, 118, 120, 121, 123, 125, 126, 135, 136, 137, 138, 139, 140, 142, 144, 146, 148, 150, 152, 154, 155, 157, 158, 160, 163, 164, 166, 167, 169, 170, 179, 180, 181, 182, 183, 184, 190, 198, 199, 201, 202, 204, 206, 208, 216, 218, 225, 227, 234, 239, 240, 241, 243, 244, 246, 247, 249, 252, 268, 269, 270, 271, 273, 274, 275, 276, 279, 281, 282, 288, 289, 290, 291, 294, 303, 306, 307, 310, 311, 314, 335, 338, 340, 343, 345, 354, 355, 357, 358, 360, 363, 395, 396, 397, 402, 403, 404, 410, 411], "summary": {"covered_lines": 143, "num_statements": 166, "percent_covered": 86.144578313253, "percent_covered_display": "86", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [26, 27, 46, 47, 56, 94, 99, 104, 185, 186, 336, 341, 370, 375, 377, 378, 380, 381, 382, 383, 385, 392, 399], "excluded_lines": [], "functions": {"floor_at_decimal": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [46, 47], "excluded_lines": []}, "ceil_at_decimal": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [56], "excluded_lines": []}, "floor_to_step": {"executed_lines": [61], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ceil_to_step": {"executed_lines": [66], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "clean_and_check": {"executed_lines": [74, 75, 76, 77, 78], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AbstractDistribution.draw": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [94], "excluded_lines": []}, "AbstractDistribution.left_percentile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [99], "excluded_lines": []}, "AbstractDistribution.right_percentile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [104], "excluded_lines": []}, "AbstractDistribution._get_label": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AbstractDistribution.label": {"executed_lines": [112], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.values": {"executed_lines": [123], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.from_hdf5": {"executed_lines": [135, 136, 137, 138, 139, 140], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.left_percentile": {"executed_lines": [144], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.right_percentile": {"executed_lines": [148], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Histogram.draw": {"executed_lines": [152, 154, 155, 157, 158, 160], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.from_hdf5": {"executed_lines": [179, 180, 181, 182, 183, 184, 190], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [185, 186], "excluded_lines": []}, "BetaPosterior._get_label": {"executed_lines": [199], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.num_fail": {"executed_lines": [204], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.pdf": {"executed_lines": [208], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.left_percentile": {"executed_lines": [218], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.right_percentile": {"executed_lines": [227], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior.draw": {"executed_lines": [239, 240, 241, 243, 244, 246, 247, 249], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_size": {"executed_lines": [268, 269, 270, 271, 273, 274, 275, 276], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_label": {"executed_lines": [281, 282, 288, 289, 290, 291], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_xlims": {"executed_lines": [303, 306, 307, 310, 311], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "draw": {"executed_lines": [335, 338, 340, 343, 345, 354, 355, 357, 358, 360], "summary": {"covered_lines": 10, "num_statements": 12, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [336, 341], "excluded_lines": []}, "split_legends": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [370, 375, 377, 378, 380, 381, 382, 383, 385, 392], "excluded_lines": []}, "use_mpl_stylesheet": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [399], "excluded_lines": []}, "save_figure": {"executed_lines": [410, 411], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 25, 30, 37, 38, 41, 50, 59, 64, 69, 81, 84, 85, 87, 88, 89, 91, 92, 96, 97, 101, 102, 106, 109, 110, 115, 116, 118, 120, 121, 125, 126, 142, 146, 150, 163, 164, 166, 167, 169, 170, 198, 201, 202, 206, 216, 225, 234, 252, 279, 294, 314, 363, 395, 396, 397, 402, 403, 404], "summary": {"covered_lines": 69, "num_statements": 71, "percent_covered": 97.1830985915493, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [26, 27], "excluded_lines": []}}, "classes": {"AbstractDistribution": {"executed_lines": [112], "summary": {"covered_lines": 1, "num_statements": 4, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [94, 99, 104], "excluded_lines": []}, "Histogram": {"executed_lines": [123, 135, 136, 137, 138, 139, 140, 144, 148, 152, 154, 155, 157, 158, 160], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BetaPosterior": {"executed_lines": [179, 180, 181, 182, 183, 184, 190, 199, 204, 208, 218, 227, 239, 240, 241, 243, 244, 246, 247, 249], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [185, 186], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 25, 30, 37, 38, 41, 50, 59, 61, 64, 66, 69, 74, 75, 76, 77, 78, 81, 84, 85, 87, 88, 89, 91, 92, 96, 97, 101, 102, 106, 109, 110, 115, 116, 118, 120, 121, 125, 126, 142, 146, 150, 163, 164, 166, 167, 169, 170, 198, 201, 202, 206, 216, 225, 234, 252, 268, 269, 270, 271, 273, 274, 275, 276, 279, 281, 282, 288, 289, 290, 291, 294, 303, 306, 307, 310, 311, 314, 335, 338, 340, 343, 345, 354, 355, 357, 358, 360, 363, 395, 396, 397, 402, 403, 404, 410, 411], "summary": {"covered_lines": 107, "num_statements": 125, "percent_covered": 85.6, "percent_covered_display": "86", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [26, 27, 46, 47, 56, 336, 341, 370, 375, 377, 378, 380, 381, 382, 383, 385, 392, 399], "excluded_lines": []}}}, "src/lyscripts/sample.py": {"executed_lines": [1, 19, 21, 22, 23, 25, 27, 29, 30, 31, 32, 34, 38, 40, 41, 42, 43, 44, 45, 46, 47, 49, 60, 63, 64, 66, 68, 69, 71, 73, 75, 78, 79, 81, 83, 84, 85, 86, 89, 90, 92, 93, 95, 97, 98, 100, 101, 103, 106, 107, 109, 110, 112, 114, 115, 117, 118, 120, 123, 126, 135, 140, 141, 142, 146, 147, 148, 150, 153, 162, 163, 175, 184, 185, 187, 190, 193, 209, 215, 217, 225, 257, 258, 260, 261, 262, 264, 265, 267, 268, 269, 270, 275, 277, 278, 280, 291, 297, 298, 300, 304, 305, 307, 311, 316, 322, 325, 327, 328, 334, 347, 348, 350, 351, 352, 359, 365, 366, 368, 385, 387, 391, 392, 393, 394, 395, 398, 400, 401, 402, 410, 419], "summary": {"covered_lines": 125, "num_statements": 136, "percent_covered": 91.91176470588235, "percent_covered_display": "92", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [35, 36, 74, 132, 172, 188, 301, 309, 313, 420, 421], "excluded_lines": [], "functions": {"CompletedItersColumn.__init__": {"executed_lines": [68, 69], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "CompletedItersColumn.render": {"executed_lines": [73, 75], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [74], "excluded_lines": []}, "ItersPerSecondColumn.render": {"executed_lines": [83, 84, 85, 86], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AcorTime.update": {"executed_lines": [97, 98], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AcorTime.relative_diff": {"executed_lines": [103], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NumAccepted.update": {"executed_lines": [114, 115], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NumAccepted.newly_accepted": {"executed_lines": [120], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "log_prob_fn": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [132], "excluded_lines": []}, "ensure_initial_state": {"executed_lines": [140, 141, 142, 146, 147, 148, 150], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ensure_history_table": {"executed_lines": [162, 163], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [172], "excluded_lines": []}, "update_history_table": {"executed_lines": [184, 185, 187, 190], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [188], "excluded_lines": []}, "is_converged": {"executed_lines": [209], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_get_columns": {"executed_lines": [217], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "run_sampling": {"executed_lines": [257, 258, 260, 261, 262, 264, 265, 267, 268, 269, 270, 275, 277, 278, 280, 291, 297, 298, 300], "summary": {"covered_lines": 19, "num_statements": 20, "percent_covered": 95.0, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [301], "excluded_lines": []}, "DummyPool.__enter__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [309], "excluded_lines": []}, "DummyPool.__exit__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [313], "excluded_lines": []}, "get_pool": {"executed_lines": [322], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "init_sampler": {"executed_lines": [327, 328, 334], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SampleCLI.cli_cmd": {"executed_lines": [385, 387, 391, 392, 393, 394, 395, 398, 400, 401, 402, 410], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 19, 21, 22, 23, 25, 27, 29, 30, 31, 32, 34, 38, 40, 41, 42, 43, 44, 45, 46, 47, 49, 60, 63, 64, 66, 71, 78, 79, 81, 89, 90, 92, 93, 95, 100, 101, 106, 107, 109, 110, 112, 117, 118, 123, 126, 135, 153, 175, 193, 215, 225, 304, 305, 307, 311, 316, 325, 347, 348, 350, 351, 352, 359, 365, 366, 368, 419], "summary": {"covered_lines": 61, "num_statements": 65, "percent_covered": 93.84615384615384, "percent_covered_display": "94", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [35, 36, 420, 421], "excluded_lines": []}}, "classes": {"CompletedItersColumn": {"executed_lines": [68, 69, 73, 75], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [74], "excluded_lines": []}, "ItersPerSecondColumn": {"executed_lines": [83, 84, 85, 86], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AcorTime": {"executed_lines": [97, 98, 103], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NumAccepted": {"executed_lines": [114, 115, 120], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyPool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [309, 313], "excluded_lines": []}, "SampleCLI": {"executed_lines": [385, 387, 391, 392, 393, 394, 395, 398, 400, 401, 402, 410], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 19, 21, 22, 23, 25, 27, 29, 30, 31, 32, 34, 38, 40, 41, 42, 43, 44, 45, 46, 47, 49, 60, 63, 64, 66, 71, 78, 79, 81, 89, 90, 92, 93, 95, 100, 101, 106, 107, 109, 110, 112, 117, 118, 123, 126, 135, 140, 141, 142, 146, 147, 148, 150, 153, 162, 163, 175, 184, 185, 187, 190, 193, 209, 215, 217, 225, 257, 258, 260, 261, 262, 264, 265, 267, 268, 269, 270, 275, 277, 278, 280, 291, 297, 298, 300, 304, 305, 307, 311, 316, 322, 325, 327, 328, 334, 347, 348, 350, 351, 352, 359, 365, 366, 368, 419], "summary": {"covered_lines": 99, "num_statements": 107, "percent_covered": 92.5233644859813, "percent_covered_display": "93", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [35, 36, 132, 172, 188, 301, 420, 421], "excluded_lines": []}}}, "src/lyscripts/schedule.py": {"executed_lines": [1, 13, 15, 16, 17, 19, 20, 23, 30, 38, 48, 55, 56, 58, 62, 66, 71, 83], "summary": {"covered_lines": 16, "num_statements": 29, "percent_covered": 55.172413793103445, "percent_covered_display": "55", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [25, 26, 27, 35, 44, 45, 73, 75, 76, 78, 80, 84, 85], "excluded_lines": [], "functions": {"geometric_schedule": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [25, 26, 27], "excluded_lines": []}, "linear_schedule": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [35], "excluded_lines": []}, "power_schedule": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [44, 45], "excluded_lines": []}, "ScheduleCLI.cli_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [73, 75, 76, 78, 80], "excluded_lines": []}, "": {"executed_lines": [1, 13, 15, 16, 17, 19, 20, 23, 30, 38, 48, 55, 56, 58, 62, 66, 71, 83], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [84, 85], "excluded_lines": []}}, "classes": {"ScheduleCLI": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [73, 75, 76, 78, 80], "excluded_lines": []}, "": {"executed_lines": [1, 13, 15, 16, 17, 19, 20, 23, 30, 38, 48, 55, 56, 58, 62, 66, 71, 83], "summary": {"covered_lines": 16, "num_statements": 24, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [25, 26, 27, 35, 44, 45, 84, 85], "excluded_lines": []}}}, "src/lyscripts/schema.py": {"executed_lines": [1, 27, 29, 30, 32, 35, 36, 38, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 58, 64], "summary": {"covered_lines": 18, "num_statements": 21, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [60, 61, 65], "excluded_lines": [], "functions": {"main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [60, 61], "excluded_lines": []}, "": {"executed_lines": [1, 27, 29, 30, 32, 35, 36, 38, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 58, 64], "summary": {"covered_lines": 18, "num_statements": 19, "percent_covered": 94.73684210526316, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [65], "excluded_lines": []}}, "classes": {"SchemaSettings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 27, 29, 30, 32, 35, 36, 38, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 58, 64], "summary": {"covered_lines": 18, "num_statements": 21, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [60, 61, 65], "excluded_lines": []}}}, "src/lyscripts/utils.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 18, 21, 23, 24, 26, 27, 30, 33, 42, 43, 45, 46, 47, 48, 50, 53, 63, 65, 66, 67, 68, 70, 72, 75, 91, 93, 94, 95, 97, 98, 100, 102, 105, 115, 117, 118, 119, 120, 122, 124, 127, 137, 138, 139, 140, 143, 146, 151, 152, 154, 155, 156, 159, 160, 162, 163, 164, 165, 168, 169, 177, 178, 179, 180, 183, 184, 192, 193, 195, 199], "summary": {"covered_lines": 79, "num_statements": 84, "percent_covered": 94.04761904761905, "percent_covered_display": "94", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [25, 141, 142, 196, 197], "excluded_lines": [], "functions": {"binom_pmf": {"executed_lines": [23, 24, 26, 27, 30], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [25], "excluded_lines": []}, "get_dict_depth": {"executed_lines": [42, 43, 45, 46, 47, 48, 50], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "delete_private_keys": {"executed_lines": [63, 65, 66, 67, 68, 70, 72], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "flatten": {"executed_lines": [91, 93, 94, 95, 97, 98, 100, 102], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "unflatten": {"executed_lines": [115, 117, 118, 119, 120, 122, 124], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_modalities_subset": {"executed_lines": [137, 138, 139, 140, 143], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [141, 142], "excluded_lines": []}, "load_patient_data": {"executed_lines": [151, 152, 154, 155, 156], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "load_yaml_params": {"executed_lines": [162, 163, 164, 165], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "load_model_samples": {"executed_lines": [177, 178, 179, 180], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_hdf5_backend": {"executed_lines": [192, 193, 195, 199], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [196, 197], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 18, 21, 33, 53, 75, 105, 127, 146, 159, 160, 168, 169, 183, 184], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 18, 21, 23, 24, 26, 27, 30, 33, 42, 43, 45, 46, 47, 48, 50, 53, 63, 65, 66, 67, 68, 70, 72, 75, 91, 93, 94, 95, 97, 98, 100, 102, 105, 115, 117, 118, 119, 120, 122, 124, 127, 137, 138, 139, 140, 143, 146, 151, 152, 154, 155, 156, 159, 160, 162, 163, 164, 165, 168, 169, 177, 178, 179, 180, 183, 184, 192, 193, 195, 199], "summary": {"covered_lines": 79, "num_statements": 84, "percent_covered": 94.04761904761905, "percent_covered_display": "94", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [25, 141, 142, 196, 197], "excluded_lines": []}}}}, "totals": {"covered_lines": 1178, "num_statements": 1577, "percent_covered": 74.6987951807229, "percent_covered_display": "75", "missing_lines": 399, "excluded_lines": 0}}, "coverage_path": "."} \ No newline at end of file diff --git a/htmlcov/class_index.html b/htmlcov/class_index.html index 7e51ec3..ba51c2d 100644 --- a/htmlcov/class_index.html +++ b/htmlcov/class_index.html @@ -54,8 +54,8 @@

Classes

- coverage.py v7.9.1, - created at 2025-06-26 14:44 +0000 + coverage.py v7.9.2, + created at 2025-07-23 06:01 +0000

@@ -153,8 +153,8 @@

93% - src/lyscripts/compute/prevalences.py - PrevalencesCLI + src/lyscripts/compute/prevalences.py + PrevalencesCLI 19 0 0 @@ -163,10 +163,10 @@

src/lyscripts/compute/prevalences.py (no class) - 61 + 63 7 0 - 89% + 89% src/lyscripts/compute/priors.py @@ -297,8 +297,8 @@

92% - src/lyscripts/data/__init__.py - DataCLI + src/lyscripts/data/__init__.py + DataCLI 1 1 0 @@ -307,10 +307,10 @@

src/lyscripts/data/__init__.py (no class) - 11 + 12 0 0 - 100% + 100% src/lyscripts/data/__main__.py @@ -336,6 +336,22 @@

0 89% + + src/lyscripts/data/fetch.py + FetchCLI + 5 + 5 + 0 + 0% + + + src/lyscripts/data/fetch.py + (no class) + 16 + 2 + 0 + 88% + src/lyscripts/data/filter.py FilterCLI @@ -385,8 +401,8 @@

85% - src/lyscripts/data/lyproxify.py - LyproxifyCLI + src/lyscripts/data/lyproxify.py + LyproxifyCLI 17 17 0 @@ -395,10 +411,10 @@

src/lyscripts/data/lyproxify.py (no class) - 104 + 106 50 0 - 52% + 53% src/lyscripts/data/split.py @@ -565,10 +581,10 @@

Total   - 1551 - 392 + 1577 + 399 0 - 75% + 75% @@ -580,8 +596,8 @@

- coverage.py v7.9.1, - created at 2025-06-26 14:44 +0000 + coverage.py v7.9.2, + created at 2025-07-23 06:01 +0000

diff --git a/htmlcov/z_055061514423972c_prevalences_py.html b/htmlcov/z_055061514423972c_prevalences_py.html index 51f0c9e..a1fd050 100644 --- a/htmlcov/z_055061514423972c_prevalences_py.html +++ b/htmlcov/z_055061514423972c_prevalences_py.html @@ -54,8 +54,8 @@

- 80 statements   - + 82 statements   +

@@ -64,8 +64,8 @@

^ index     » next       - coverage.py v7.9.1, - created at 2025-06-26 14:44 +0000 + coverage.py v7.9.2, + created at 2025-07-23 06:01 +0000