Skip to content

Codex/multisess track2p convenience v2#1806

Closed
FlorianPfaff wants to merge 12 commits intomainfrom
codex/multisess-track2p-convenience-v2
Closed

Codex/multisess track2p convenience v2#1806
FlorianPfaff wants to merge 12 commits intomainfrom
codex/multisess-track2p-convenience-v2

Conversation

@FlorianPfaff
Copy link
Copy Markdown
Owner

No description provided.

FlorianPfaff and others added 12 commits April 20, 2026 04:50
Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/c4d8e0ab-3207-4176-8206-ae8ce08944b4

Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com>
Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/4d3a0fe3-bb75-4da9-91ed-f7b7b542192b

Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown

MegaLinter analysis: Error

Descriptor Linter Files Fixed Errors Warnings Elapsed time
✅ COPYPASTE jscpd yes no no 11.86s
✅ JSON prettier 2 0 0 0 0.48s
✅ JSON v8r 2 0 0 2.34s
✅ MARKDOWN markdownlint 2 0 0 0 0.72s
✅ MARKDOWN markdown-table-formatter 2 0 0 0 0.26s
✅ PYTHON bandit 353 0 0 5.49s
✅ PYTHON black 353 9 0 0 8.82s
❌ PYTHON flake8 353 8 0 3.05s
✅ PYTHON isort 353 10 0 0 0.7s
❌ PYTHON mypy 353 3 0 5.01s
❌ PYTHON pylint 353 28 0 109.58s
❌ PYTHON ruff 353 10 8 0 0.18s
✅ REPOSITORY checkov yes no no 22.42s
✅ REPOSITORY gitleaks yes no no 6.23s
✅ REPOSITORY git_diff yes no no 0.21s
✅ REPOSITORY secretlint yes no no 7.11s
✅ REPOSITORY syft yes no no 5.13s
✅ REPOSITORY trivy-sbom yes no no 2.32s
✅ REPOSITORY trufflehog yes no no 18.61s
✅ YAML prettier 4 0 0 0 0.49s
✅ YAML v8r 4 0 0 4.76s
✅ YAML yamllint 4 0 0 0.45s

Detailed Issues

❌ PYTHON / flake8 - 8 errors
pyrecest/tests/test_multisession_assignment.py:157:15: F821 undefined name 'np'
pyrecest/tests/test_multisession_assignment.py:164:22: F821 undefined name 'np'
pyrecest/tests/test_multisession_assignment.py:167:23: F821 undefined name 'np'
pyrecest/tests/test_multisession_assignment.py:172:23: F821 undefined name 'multisession_assignment_module'
pyrecest/tests/test_multisession_assignment.py:179:13: F821 undefined name 'multisession_assignment_module'
pyrecest/tests/test_multisession_assignment.py:196:13: F821 undefined name 'np'
pyrecest/tests/test_multisession_assignment.py:197:13: F821 undefined name 'np'
pyrecest/tests/test_multisession_assignment.py:201:13: F821 undefined name 'multisession_assignment_module'
❌ PYTHON / mypy - 3 errors
pyrecest/utils/multisession_assignment_observation_costs.py:20: error: Variable "pyrecest.utils.multisession_assignment_observation_costs.ObservationCostValue" is not valid as a type  [valid-type]
pyrecest/utils/multisession_assignment_observation_costs.py:20: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
pyrecest/utils/multisession_assignment_observation_costs.py:214: error: Variable "pyrecest.utils.multisession_assignment_observation_costs.ObservationCostValue" is not valid as a type  [valid-type]
pyrecest/utils/multisession_assignment_observation_costs.py:214: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
pyrecest/utils/multisession_assignment_observation_costs.py:252: error: Variable "pyrecest.utils.multisession_assignment_observation_costs.ObservationCostValue" is not valid as a type  [valid-type]
pyrecest/utils/multisession_assignment_observation_costs.py:252: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
pyrecest/smoothers/unscented_rauch_tung_striebel_smoother.py:51: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
Found 3 errors in 1 file (checked 353 source files)
❌ PYTHON / pylint - 28 errors
************* Module pyrecest.tests.test_multisession_assignment
pyrecest/tests/test_multisession_assignment.py:155:14: E0602: Undefined variable 'np' (undefined-variable)
pyrecest/tests/test_multisession_assignment.py:160:21: E0602: Undefined variable 'np' (undefined-variable)
pyrecest/tests/test_multisession_assignment.py:161:22: E0602: Undefined variable 'np' (undefined-variable)
pyrecest/tests/test_multisession_assignment.py:164:22: W0212: Access to a protected member _solve_max_weight_matching of a client class (protected-access)
pyrecest/tests/test_multisession_assignment.py:164:22: E0602: Undefined variable 'multisession_assignment_module' (undefined-variable)
pyrecest/tests/test_multisession_assignment.py:170:23: W0212: Access to a protected member _solve_max_weight_matching_via_linprog of a client class (protected-access)
pyrecest/tests/test_multisession_assignment.py:170:23: E0602: Undefined variable 'multisession_assignment_module' (undefined-variable)
pyrecest/tests/test_multisession_assignment.py:177:8: E1101: Instance of 'TestMultiSessionAssignment' has no '_assert_valid_matching' member (no-member)
pyrecest/tests/test_multisession_assignment.py:178:8: E1101: Instance of 'TestMultiSessionAssignment' has no '_assert_valid_matching' member (no-member)
pyrecest/tests/test_multisession_assignment.py:186:12: E0602: Undefined variable 'np' (undefined-variable)
pyrecest/tests/test_multisession_assignment.py:187:12: E0602: Undefined variable 'np' (undefined-variable)
pyrecest/tests/test_multisession_assignment.py:191:12: E0602: Undefined variable 'multisession_assignment_module' (undefined-variable)
************* Module pyrecest.utils.multisession_assignment
pyrecest/utils/multisession_assignment.py:524:0: R0914: Too many local variables (17/15) (too-many-locals)
pyrecest/utils/multisession_assignment.py:542:15: E0601: Using variable 'np' before assignment (used-before-assignment)
************* Module pyrecest.utils.multisession_assignment_observation_costs
pyrecest/utils/multisession_assignment_observation_costs.py:22:0: R0913: Too many arguments (8/6) (too-many-arguments)
pyrecest/utils/multisession_assignment_observation_costs.py:22:0: R0914: Too many local variables (23/15) (too-many-locals)
pyrecest/utils/multisession_assignment_observation_costs.py:206:22: R1721: Unnecessary use of a comprehension, use dict(enumerate(observation_costs)) instead. (unnecessary-comprehension)
pyrecest/utils/multisession_assignment_observation_costs.py:254:0: R0913: Too many arguments (8/6) (too-many-arguments)
pyrecest/utils/multisession_assignment_observation_costs.py:254:0: R0914: Too many local variables (19/15) (too-many-locals)
************* Module update_init_helper
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.utils.multisession_assignment:[365:416]
==pyrecest.utils.multisession_assignment_observation_costs:[145:200]
        if matrix.ndim != 2:
            raise ValueError("Each pairwise cost matrix must be two-dimensional.")
        normalized[(session_idx, session_idx + 1)] = matrix
    return normalized


def _normalize_session_sizes(
    session_sizes: SessionSizesInput | None,
) -> dict[int, int]:
    if session_sizes is None:
        return {}
    if isinstance(session_sizes, Mapping):
        normalized = {int(session_idx): int(size) for session_idx, size in session_sizes.items()}
    else:
        normalized = {session_idx: int(size) for session_idx, size in enumerate(session_sizes)}
    for session_idx, size in normalized.items():
        if size < 0:
            raise ValueError(f"Session {session_idx} has a negative detection count.")
    return normalized


def _infer_and_validate_session_sizes(
    pairwise_costs: Mapping[tuple[int, int], np.ndarray],
    session_sizes: Mapping[int, int],
) -> dict[int, int]:
    inferred_sizes = dict(session_sizes)
    for (source_session, target_session), cost_matrix in pairwise_costs.items():
        source_size, target_size = cost_matrix.shape
        _check_or_set_session_size(inferred_sizes, source_session, source_size)
        _check_or_set_session_size(inferred_sizes, target_session, target_size)
    if not inferred_sizes and not pairwise_costs:
        raise ValueError("No observations were provided. Supply pairwise_costs or session_sizes.")
    return dict(sorted(inferred_sizes.items()))


def _check_or_set_session_size(
    inferred_sizes: dict[int, int],
    session_idx: int,
    candidate_size: int,
) -> None:
    if session_idx in inferred_sizes and inferred_sizes[session_idx] != candidate_size:
        raise ValueError(
            f"Inconsistent detection count for session {session_idx}: "
            f"expected {inferred_sizes[session_idx]}, got {candidate_size}."
        )
    inferred_sizes[session_idx] = int(candidate_size)


def _normalize_observation_costs(
    observation_costs: ObservationCostsInput | None,
    session_sizes: Mapping[int, int],
    *,
    default_value: float,
    name: str,
) -> dict[int, np.ndarray]: (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.utils.nonrigid_point_set_registration:[211:221]
==pyrecest.utils.point_set_registration:[241:251]
    costs = asarray(cost_matrix)
    if costs.ndim != 2:
        raise ValueError("cost_matrix must be two-dimensional.")
    if costs.shape[0] == 0:
        return zeros((0,), dtype=int64)
    if costs.shape[1] == 0:
        return zeros((costs.shape[0],), dtype=int64) - 1

    finite_mask = isfinite(costs)
    finite_costs = costs[finite_mask] (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.utils.multisession_assignment:[348:356]
==pyrecest.utils.multisession_assignment_observation_costs:[128:136]
    if isinstance(pairwise_costs, Mapping):
        normalized: dict[tuple[int, int], np.ndarray] = {}
        for key, value in pairwise_costs.items():
            if len(key) != 2:
                raise ValueError("Each pairwise-cost key must contain two session indices.")
            source_session, target_session = int(key[0]), int(key[1])
            if source_session >= target_session:
                raise ValueError("Pairwise-cost keys must satisfy source_session < target_session.") (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.utils.nonrigid_point_set_registration:[124:135]
==pyrecest.utils.point_set_registration:[107:118]
    assignment: Any
    matched_reference_indices: Any
    matched_moving_indices: Any
    transformed_reference_points: Any
    matched_costs: Any
    rmse: float
    n_iterations: int
    converged: bool


def _as_point_array(points): (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.utils.nonrigid_point_set_registration:[319:329]
==pyrecest.utils.point_set_registration:[390:400]
    association_cost = _default_cost if cost_function is None else cost_function

    for iteration in range(1, max_iterations + 1):
        transformed_reference = transform.apply(reference)
        current_costs = asarray(association_cost(transformed_reference, moving))
        if current_costs.shape != (reference.shape[0], moving.shape[0]):
            raise ValueError(
                "cost_function must return an array of shape (n_reference, n_moving)."
            )
 (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.utils.multisession_assignment:[357:364]
==pyrecest.utils.multisession_assignment_observation_costs:[137:144]
            if matrix.ndim != 2:
                raise ValueError("Each pairwise cost matrix must be two-dimensional.")
            normalized[(source_session, target_session)] = matrix
        return normalized

    normalized = {}
    for session_idx, value in enumerate(pairwise_costs): (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.utils.multisession_assignment:[463:469]
==pyrecest.utils.multisession_assignment_observation_costs:[266:272]
        source_position = session_positions[source_session]
        target_position = session_positions[target_session]
        gap = target_position - source_position - 1
        if gap < 0:
            raise ValueError("Session indices must define a forward-in-time edge ordering.")
 (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.utils.nonrigid_point_set_registration:[146:154]
==pyrecest.utils.point_set_registration:[129:137]
    source = _as_point_array(source_points)
    target = _as_point_array(target_points)
    if source.shape != target.shape:
        raise ValueError("source_points and target_points must have the same shape.")
    return source, target


def _normalize_weights(weights, n_points): (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.utils.nonrigid_point_set_registration:[230:236]
==pyrecest.utils.point_set_registration:[262:268]
    row_indices, col_indices = linear_sum_assignment(padded_costs)

    assignment = zeros((costs.shape[0],), dtype=int64) - 1
    for row_index, col_index in zip(row_indices, col_indices):
        if row_index >= costs.shape[0] or col_index >= costs.shape[1]:
            continue (duplicate-code)

-----------------------------------
Your code has been rated at 9.97/10
❌ PYTHON / ruff - 8 errors
F821 Undefined name `np`
   --> pyrecest/tests/test_multisession_assignment.py:157:15
    |
156 |     def test_sparse_backend_matches_previous_linprog_backend(self):
157 |         rng = np.random.default_rng(42)
    |               ^^
158 |         num_nodes = 12
159 |         all_pairs = [
    |

F821 Undefined name `np`
   --> pyrecest/tests/test_multisession_assignment.py:164:22
    |
162 |         selected_pairs = rng.choice(len(all_pairs), size=40, replace=False)
163 |
164 |         left_nodes = np.array(
    |                      ^^
165 |             [all_pairs[index][0] for index in selected_pairs], dtype=int
166 |         )
    |

F821 Undefined name `np`
   --> pyrecest/tests/test_multisession_assignment.py:167:23
    |
165 |             [all_pairs[index][0] for index in selected_pairs], dtype=int
166 |         )
167 |         right_nodes = np.array(
    |                       ^^
168 |             [all_pairs[index][1] for index in selected_pairs], dtype=int
169 |         )
    |

F821 Undefined name `multisession_assignment_module`
   --> pyrecest/tests/test_multisession_assignment.py:172:23
    |
170 |         edge_gains = rng.uniform(0.1, 10.0, size=selected_pairs.size)
171 |
172 |         sparse_mask = multisession_assignment_module._solve_max_weight_matching(
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
173 |             left_nodes,
174 |             right_nodes,
    |

F821 Undefined name `multisession_assignment_module`
   --> pyrecest/tests/test_multisession_assignment.py:179:13
    |
177 |         )
178 |         linprog_mask = (
179 |             multisession_assignment_module._solve_max_weight_matching_via_linprog(
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
180 |                 left_nodes,
181 |                 right_nodes,
    |

F821 Undefined name `np`
   --> pyrecest/tests/test_multisession_assignment.py:196:13
    |
194 |     def test_sparse_backend_falls_back_to_linprog_when_requested(self):
195 |         pairwise_costs = [
196 |             np.array([[0.1, 8.0], [8.0, 0.2]], dtype=float),
    |             ^^
197 |             np.array([[0.1, 8.0], [8.0, 0.2]], dtype=float),
198 |         ]
    |

F821 Undefined name `np`
   --> pyrecest/tests/test_multisession_assignment.py:197:13
    |
195 |         pairwise_costs = [
196 |             np.array([[0.1, 8.0], [8.0, 0.2]], dtype=float),
197 |             np.array([[0.1, 8.0], [8.0, 0.2]], dtype=float),
    |             ^^
198 |         ]
    |

F821 Undefined name `multisession_assignment_module`
   --> pyrecest/tests/test_multisession_assignment.py:201:13
    |
200 |         with patch.object(
201 |             multisession_assignment_module,
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
202 |             "min_weight_full_bipartite_matching",
203 |             side_effect=ValueError("forced sparse-backend failure"),
    |

Found 8 errors.

See detailed reports in MegaLinter artifacts

Your project could benefit from a custom flavor, which would allow you to run only the linters you need, and thus improve runtime performances. (Skip this info by defining FLAVOR_SUGGESTIONS: false)

  • Documentation: Custom Flavors
  • Command: npx mega-linter-runner@9.4.0 --custom-flavor-setup --custom-flavor-linters PYTHON_PYLINT,PYTHON_BLACK,PYTHON_FLAKE8,PYTHON_ISORT,PYTHON_BANDIT,PYTHON_MYPY,PYTHON_RUFF,COPYPASTE_JSCPD,JSON_V8R,JSON_PRETTIER,MARKDOWN_MARKDOWNLINT,MARKDOWN_MARKDOWN_TABLE_FORMATTER,REPOSITORY_CHECKOV,REPOSITORY_GIT_DIFF,REPOSITORY_GITLEAKS,REPOSITORY_SECRETLINT,REPOSITORY_SYFT,REPOSITORY_TRIVY_SBOM,REPOSITORY_TRUFFLEHOG,YAML_PRETTIER,YAML_YAMLLINT,YAML_V8R

MegaLinter is graciously provided by OX Security
Show us your support by starring ⭐ the repository

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants