ortools.math_opt.python.from_model

Utilities for finding the model associated with a variable/constraint etc.

This file is an implementation detail and not part of the MathOpt public API.

 1# Copyright 2010-2025 Google LLC
 2# Licensed under the Apache License, Version 2.0 (the "License");
 3# you may not use this file except in compliance with the License.
 4# You may obtain a copy of the License at
 5#
 6#     http://www.apache.org/licenses/LICENSE-2.0
 7#
 8# Unless required by applicable law or agreed to in writing, software
 9# distributed under the License is distributed on an "AS IS" BASIS,
10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11# See the License for the specific language governing permissions and
12# limitations under the License.
13
14"""Utilities for finding the model associated with a variable/constraint etc.
15
16This file is an implementation detail and not part of the MathOpt public API.
17"""
18
19from typing import Protocol
20from ortools.math_opt.python.elemental import elemental
21
22
23class FromModel(Protocol):
24
25    __slots__ = ()
26
27    @property
28    def elemental(self) -> elemental.Elemental: ...
29
30
31def model_is_same(e1: FromModel, e2: FromModel) -> None:
32    if e1.elemental is not e2.elemental:
33        raise ValueError(
34            f"Expected two elements from the same model, but observed {e1} from"
35            f" model named: '{e1.elemental.model_name!r}', and {e2} from model"
36            f" named: '{e2.elemental.model_name!r}'."
37        )
class FromModel(typing.Protocol):
24class FromModel(Protocol):
25
26    __slots__ = ()
27
28    @property
29    def elemental(self) -> elemental.Elemental: ...

Base class for protocol classes.

Protocol classes are defined as::

class Proto(Protocol):
    def meth(self) -> int:
        ...

Such classes are primarily used with static type checkers that recognize structural subtyping (static duck-typing).

For example::

class C:
    def meth(self) -> int:
        return 0

def func(x: Proto) -> int:
    return x.meth()

func(C())  # Passes static type check

See PEP 544 for details. Protocol classes decorated with @typing.runtime_checkable act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. Protocol classes can be generic, they are defined as::

class GenProto[T](Protocol):
    def meth(self) -> T:
        ...
FromModel(*args, **kwargs)
1945def _no_init_or_replace_init(self, *args, **kwargs):
1946    cls = type(self)
1947
1948    if cls._is_protocol:
1949        raise TypeError('Protocols cannot be instantiated')
1950
1951    # Already using a custom `__init__`. No need to calculate correct
1952    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1953    if cls.__init__ is not _no_init_or_replace_init:
1954        return
1955
1956    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1957    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1958    # searches for a proper new `__init__` in the MRO. The new `__init__`
1959    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1960    # instantiation of the protocol subclass will thus use the new
1961    # `__init__` and no longer call `_no_init_or_replace_init`.
1962    for base in cls.__mro__:
1963        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1964        if init is not _no_init_or_replace_init:
1965            cls.__init__ = init
1966            break
1967    else:
1968        # should not happen
1969        cls.__init__ = object.__init__
1970
1971    cls.__init__(self, *args, **kwargs)
28    @property
29    def elemental(self) -> elemental.Elemental: ...
def model_is_same( e1: FromModel, e2: FromModel) -> None:
32def model_is_same(e1: FromModel, e2: FromModel) -> None:
33    if e1.elemental is not e2.elemental:
34        raise ValueError(
35            f"Expected two elements from the same model, but observed {e1} from"
36            f" model named: '{e1.elemental.model_name!r}', and {e2} from model"
37            f" named: '{e2.elemental.model_name!r}'."
38        )