Skip to content

Static type-checking errors caused by numbers.Real annotations #427

Description

@brunopasseti

Describe the bug

Since commit f65eb951, Python-MIP annotations uses numbers.Real for type annotations.

However, it causes false-positive in static type checkers such as mypy and Pylance.
Type checkers do not treat the numbers ABC hierarchy and virtual subclass registration as a usable static numeric type hierarchy.

To Reproduce

import mip


def main() -> None:
    model = mip.Model()
    y = model.add_var(name="y", lb=0.0, ub=1.0)
    xf_sum: mip.Var | mip.LinExpr = y
    big_m: float = 2.0

    model.add_constr(big_m * y >= xf_sum)
    model.optimize()

With Pylance type checking set to standard, this reports:

Operator "*" not supported for types "float" and "Var | LinExpr"
  Operator "*" not supported for types "float" and "Var"
  Operator "*" not supported for types "float" and "LinExpr"

Mypy shows the same limitation for numbers types:

__init__.py:6: error: Argument "lb" to "add_var" of "Model" has incompatible type "float"; expected "Real"  [arg-type]
__init__.py:6: note: Types from "numbers" are not supported for static type checking
__init__.py:6: note: See https://peps.python.org/pep-0484/#the-numeric-tower
__init__.py:6: note: Consider using a protocol instead, such as typing.SupportsFloat
__init__.py:6: error: Argument "ub" to "add_var" of "Model" has incompatible type "float"; expected "Real"  [arg-type]
__init__.py:10: error: Unsupported operand types for * ("float" and "Var")  [operator]

Expected behavior

Idk if this should be labelled as a bug or enhancement. If is a bug: float * mip.Var and float * mip.LinExpr, and everything else using numbers package should staticaly type-check without errors.

Desktop

  • Operating System: Windows and Linux
  • Python: 3.11.12 and 3.13.14
  • Python-MIP: 1.17.4
  • mypy: 2.3.1
  • Pylance: 2026.3.104
  • VS Code: 1.138.0
  • Type-checking mode: pylance in standard

Additional context

More information can be found in the Python and the Mypy issue linked above:

Fix?

Use type unions int | float, or the protocol typing.SupportsFloat, while retaining numbers.Real for runtime isinstance checks if needed.

If this behaviour isn't expected I can fork it/open a PR to fix it

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions