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#!/usr/bin/env python3
 2# Copyright 2010-2025 Google LLC
 3# Licensed under the Apache License, Version 2.0 (the "License");
 4# you may not use this file except in compliance with the License.
 5# You may obtain a copy of the License at
 6#
 7#     http://www.apache.org/licenses/LICENSE-2.0
 8#
 9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Utilities for finding the model associated with a variable/constraint etc.
16
17This file is an implementation detail and not part of the MathOpt public API.
18"""
19
20from typing import Protocol
21from ortools.math_opt.python.elemental import elemental
22
23
24class FromModel(Protocol):
25
26    __slots__ = ()
27
28    @property
29    def elemental(self) -> elemental.Elemental: ...
30
31
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        )
class FromModel(typing.Protocol):
25class FromModel(Protocol):
26
27    __slots__ = ()
28
29    @property
30    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)
1866def _no_init_or_replace_init(self, *args, **kwargs):
1867    cls = type(self)
1868
1869    if cls._is_protocol:
1870        raise TypeError('Protocols cannot be instantiated')
1871
1872    # Already using a custom `__init__`. No need to calculate correct
1873    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1874    if cls.__init__ is not _no_init_or_replace_init:
1875        return
1876
1877    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1878    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1879    # searches for a proper new `__init__` in the MRO. The new `__init__`
1880    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1881    # instantiation of the protocol subclass will thus use the new
1882    # `__init__` and no longer call `_no_init_or_replace_init`.
1883    for base in cls.__mro__:
1884        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1885        if init is not _no_init_or_replace_init:
1886            cls.__init__ = init
1887            break
1888    else:
1889        # should not happen
1890        cls.__init__ = object.__init__
1891
1892    cls.__init__(self, *args, **kwargs)
elemental
29    @property
30    def elemental(self) -> elemental.Elemental: ...
def model_is_same( e1: FromModel, e2: FromModel) -> None:
33def model_is_same(e1: FromModel, e2: FromModel) -> None:
34    if e1.elemental is not e2.elemental:
35        raise ValueError(
36            f"Expected two elements from the same model, but observed {e1} from"
37            f" model named: '{e1.elemental.model_name!r}', and {e2} from model"
38            f" named: '{e2.elemental.model_name!r}'."
39        )