Skip to content

fix(maths): defer Matrix type annotations so import does not NameError - #15265

Merged
cclauss merged 1 commit into
TheAlgorithms:masterfrom
sudo-ai-git:fix/matrix-exponentiation-annotations
Sep 10, 2026
Merged

fix(maths): defer Matrix type annotations so import does not NameError#15265
cclauss merged 1 commit into
TheAlgorithms:masterfrom
sudo-ai-git:fix/matrix-exponentiation-annotations

Conversation

@sudo-ai-git

Copy link
Copy Markdown
Contributor

Describe your change

  • Add an algorithm?
  • Fix a bug or typo in an existing algorithm?
  • Add or change doctests? -- Note: Please avoid changing both code and tests in a single pull request.
  • Documentation change?

Checklist

  • I have read CONTRIBUTING.md.
  • This pull request is all my own work -- I have not plagiarized.
  • I know that pull requests will not be merged if they fail the automated tests.
  • This PR only changes one algorithm file. To ease review, please open separate PRs for separate algorithms.
  • All new Python files are placed inside an existing directory.
  • All filenames are in all lowercase characters with no spaces or dashes.
  • All functions and variable names follow Python naming conventions.
  • All function parameters and return values are annotated with Python type hints.
  • All functions have doctests that pass the automated testing.
  • All new algorithms include at least one URL that points to Wikipedia or another similar explanation.
  • If this pull request resolves one or more open issues, then the description above includes the issue number(s) with a closing keyword: "Fixes #ISSUE-NUMBER".

Why

Importing maths/matrix_exponentiation.py currently raises at import time on master:

Traceback (most recent call last):
  File "<string>", line 3, in <module>
  File "maths/matrix_exponentiation.py", line 20, in Matrix
    def __mul__(self, b: Matrix) -> Matrix:
                         ^^^^^^
NameError: name 'Matrix' is not defined

__mul__ and modular_exponentiation annotate with Matrix before the name is bound in the class body, and annotations evaluate eagerly.

What

Two-line fix: add from __future__ import annotations to defer annotation evaluation — the same pattern already used across the repo. No behavior change.

This supersedes #15103 (closed; the branch was rebased so that PR could not be reopened).

Verification (on current master)

  • Before: import matrix_exponentiation -> NameError: name 'Matrix' is not defined
  • After: import succeeds, fibonacci_with_matrix_exponentiation(13, 0, 1) == 144
  • python -m doctest maths/matrix_exponentiation.py -> 10 passed, 0 failed
  • ruff check maths/matrix_exponentiation.py -> All checks passed!

Rebased onto current master per @priya-sundaram-dev's request on #15103.

Importing maths.matrix_exponentiation raised 'NameError: name Matrix is
not defined' because __mul__ and modular_exponentiation annotate with
Matrix before the class name is bound (annotations evaluate eagerly at
class-body execution time).

Add 'from __future__ import annotations' to defer annotation evaluation,
matching the pattern used elsewhere in the repo.

Verified on current master: import succeeds (NameError gone) and all 10
doctests pass.

Signed-off-by: sudo-ai-git <sudo-ai-git@users.noreply.github.com>

@priya-sundaram-dev priya-sundaram-dev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clean re-do — this is exactly the minimal fix I hoped for. Verified against the head commit:

  • Before (master): import matrix_exponentiationNameError: name 'Matrix' is not defined
  • After: import succeeds, fibonacci_with_matrix_exponentiation(13, 0, 1) == 144
  • python -m doctest maths/matrix_exponentiation.py → 10 passed, 0 failed
  • ruff / ty green

A single from __future__ import annotations is the right call here — it defers the eager evaluation of the Matrix self-references and matches the pattern already used elsewhere in the repo, with no behavior change. LGTM. 🎉 (build_docs was still pending when I looked; once it's green this is good to go from my side.)

@cclauss
cclauss merged commit df92771 into TheAlgorithms:master Sep 10, 2026
6 checks passed
@cclauss

cclauss commented Sep 10, 2026

Copy link
Copy Markdown
Member

@sudo-ai-git @priya-sundaram-dev Which Python versions is this change needed on?!?

Our pytests already pass without this change on Python 3.14t (see the file: .python-version) and on Python 3.15t.

@priya-sundaram-dev

Copy link
Copy Markdown
Contributor

Good question — I dug into the version boundary:

Needed on CPython ≤ 3.13; a no-op on 3.14+.

The module has forward references to the class from inside its own body:

  • `def mul(self, b: Matrix) -> Matrix:` (line 22)
  • `def modular_exponentiation(a: Matrix, b: int) -> Matrix:` (line 31)

On ≤3.13 function annotations are evaluated eagerly at def time, so Matrix is dereferenced before the class name is bound → NameError at import. I reproduced it on 3.12 by dropping the line:

$ python3.12 -c "import maths.matrix_exponentiation"
NameError: name 'Matrix' is not defined

On 3.14+ PEP 649 makes annotations lazily computed, so they are never evaluated at import unless something touches __annotations__ — which is exactly why our pytest run is green on 3.14t/3.15t without the change.

So this is not needed for our CI (we pin 3.14t/3.15t via .python-version), but it keeps the module importable for anyone on 3.9–3.13, and it matches the from __future__ import annotations convention already used across the repo. Harmless on new Pythons, correct on old ones — worth keeping IMO, but no objection if you prefer to revert since CI does not exercise it.

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.

3 participants