Skip to content

Commit

Permalink
Merge pull request #2912 from jsiirola/common-docs
Browse files Browse the repository at this point in the history
Update `pyomo.common` documentation
  • Loading branch information
mrmundt authored Jul 20, 2023
2 parents c70a41f + 7377920 commit abfedb9
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 50 deletions.
29 changes: 20 additions & 9 deletions doc/OnlineDocs/developer_reference/deprecation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,33 @@ Deprecation
We offer a set of tools to help with deprecation in
``pyomo.common.deprecation``.

By policy, when deprecating or moving an existing capability,
one of the following functions should be imported. In use,
the ``version`` option should be set to current development
version. This can be found by running ``pyomo --version`` on
your local fork/branch.
By policy, when deprecating or moving an existing capability, one of the
following utilities should be leveraged. Each has a required
``version`` argument that should be set to current development version (e.g.,
``"6.6.2.dev0"``). This version will be updated to the next actual
release as part of the Pyomo release process. The current development version
can be found by running ``pyomo --version`` on your local fork/branch.

.. autoclass:: pyomo.common.deprecation.deprecated
.. currentmodule:: pyomo.common.deprecation

.. autosummary::

deprecated
deprecation_warning
relocated_module
relocated_module_attribute
RenamedClass

.. autodecorator:: pyomo.common.deprecation.deprecated
:noindex:

.. autoclass:: pyomo.common.deprecation.deprecation_warning
.. autofunction:: pyomo.common.deprecation.deprecation_warning
:noindex:

.. autoclass:: pyomo.common.deprecation.relocated_module
.. autofunction:: pyomo.common.deprecation.relocated_module
:noindex:

.. autoclass:: pyomo.common.deprecation.relocated_module_attribute
.. autofunction:: pyomo.common.deprecation.relocated_module_attribute
:noindex:

.. autoclass:: pyomo.common.deprecation.RenamedClass
Expand Down
6 changes: 6 additions & 0 deletions doc/OnlineDocs/library_reference/common/errors.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pyomo.common.errors
===================

.. automodule:: pyomo.common.errors
:members:
:member-order: bysource
1 change: 1 addition & 0 deletions doc/OnlineDocs/library_reference/common/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ or rely on any other parts of Pyomo.
config.rst
dependencies.rst
deprecation.rst
errors.rst
fileutils.rst
formatting.rst
tempfiles.rst
Expand Down
80 changes: 66 additions & 14 deletions pyomo/common/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,19 @@
import warnings

from .deprecation import deprecated, deprecation_warning, in_testing_environment
from .errors import DeferredImportError
from . import numeric_types


SUPPRESS_DEPENDENCY_WARNINGS = False


class DeferredImportError(ImportError):
pass


class ModuleUnavailable(object):
"""Mock object that raises a DeferredImportError upon attribute access
"""Mock object that raises :py:class:`.DeferredImportError` upon attribute access
This object is returned by :py:func:`attempt_import()` in lieu of
the module in the case that the module import fails. Any attempts
to access attributes on this object will raise a DeferredImportError
to access attributes on this object will raise a :py:class:`.DeferredImportError`
exception.
Parameters
Expand Down Expand Up @@ -134,7 +131,7 @@ class DeferredImportModule(object):
``defer_check=True``. Any attempts to access attributes on this
object will trigger the actual module import and return either the
appropriate module attribute or else if the module import fails,
raise a DeferredImportError exception.
raise a :py:class:`.DeferredImportError` exception.
"""

Expand Down Expand Up @@ -184,6 +181,61 @@ def mro(self):


def UnavailableClass(unavailable_module):
"""Function to generate an "unavailable" base class
This function returns a custom class that wraps the
:py:class:`ModuleUnavailable` instance returned by
:py:func:`attempt_import` when the target module is not available.
Any attempt to instantiate this class (or a class derived from it)
or access a class attribute will raise the
:py:class:`.DeferredImportError` from the wrapped
:py:class:`ModuleUnavailable` object.
Parameters
----------
unavailable_module: ModuleUnavailable
The :py:class:`ModuleUnavailable` instance (from
:py:func:`attempt_import`) to use to generate the
:py:class:`.DeferredImportError`.
Example
-------
Declaring a class that inherits from an optional dependency:
.. doctest::
>>> from pyomo.common.dependencies import attempt_import, UnavailableClass
>>> bogus, bogus_available = attempt_import('bogus_unavailable_class')
>>> class MyPlugin(bogus.plugin if bogus_available else UnavailableClass(bogus)):
... pass
Attempting to instantiate the derived class generates an exception
when the module is unavailable:
.. doctest::
>>> MyPlugin()
Traceback (most recent call last):
...
pyomo.common.dependencies.DeferredImportError: The class 'MyPlugin' cannot be
created because a needed optional dependency was not found (import raised
ModuleNotFoundError: No module named 'bogus_unavailable_class')
As does attempting to access class attributes on the derived class:
.. doctest::
>>> MyPlugin.create_instance()
Traceback (most recent call last):
...
pyomo.common.dependencies.DeferredImportError: The class attribute
'MyPlugin.create_instance' is not available because a needed optional
dependency was not found (import raised ModuleNotFoundError: No module
named 'bogus_unavailable_class')
"""

class UnavailableMeta(type):
def __getattr__(cls, name):
raise DeferredImportError(
Expand Down Expand Up @@ -224,11 +276,11 @@ class DeferredImportIndicator(_DeferredImportIndicatorBase):
This object serves as a placeholder for the Boolean indicator if a
deferred module import was successful. Casting this instance to
bool will cause the import to be attempted. The actual import logic
is here and not in the DeferredImportModule to reduce the number of
attributes on the DeferredImportModule.
`bool` will cause the import to be attempted. The actual import logic
is here and not in the :py:class:`DeferredImportModule` to reduce the number of
attributes on the :py:class:`DeferredImportModule`.
``DeferredImportIndicator`` supports limited logical expressions
:py:class:`DeferredImportIndicator` supports limited logical expressions
using the ``&`` (and) and ``|`` (or) binary operators. Creating
these expressions does not trigger the import of the corresponding
:py:class:`DeferredImportModule` instances, although casting the
Expand Down Expand Up @@ -473,8 +525,8 @@ def attempt_import(
defer_check: bool, optional
If True (the default), then the attempted import is deferred
until the first use of either the module or the availability
flag. The method will return instances of DeferredImportModule
and DeferredImportIndicator.
flag. The method will return instances of :py:class:`DeferredImportModule`
and :py:class:`DeferredImportIndicator`.
deferred_submodules: Iterable[str], optional
If provided, an iterable of submodule names within this module
Expand Down Expand Up @@ -622,7 +674,7 @@ def _perform_import(


def declare_deferred_modules_as_importable(globals_dict):
"""Make all DeferredImportModules in ``globals_dict`` importable
"""Make all :py:class:`DeferredImportModules` in ``globals_dict`` importable
This function will go throughout the specified ``globals_dict``
dictionary and add any instances of :py:class:`DeferredImportModule`
Expand Down
4 changes: 0 additions & 4 deletions pyomo/common/deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,10 +389,6 @@ def relocated_module_attribute(
object from the new location (on request), as well as emitting the
deprecation warning.
It contains backports of the __getattr__ functionality for earlier
versions of Python (although the implementation for 3.5+ is more
efficient that the implementation for 2.7+)
Parameters
----------
local: str
Expand Down
86 changes: 63 additions & 23 deletions pyomo/common/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,36 @@


def format_exception(msg, prolog=None, epilog=None, exception=None, width=76):
"""Generate a formatted exception message
This returns a formatted exception message, line wrapped for display
on the console and with optional prolog and epilog messages.
Parameters
----------
msg: str
The raw exception message
prolog: str, optional
A message to output before the exception message, ``msg``. If
this message is long enough to line wrap, the ``msg`` will be
indented a level below the ``prolog`` message.
epilog: str, optional
A message to output after the exception message, ``msg``. If
provided, the ``msg`` will be indented a level below the
``prolog`` / ``epilog`` messages.
exception: Exception, optional
The raw exception being raised (used to improve initial line wrapping).
width: int, optional
The line length to wrap the exception message to.
Returns
-------
str
"""
fields = []

if epilog:
Expand Down Expand Up @@ -92,14 +122,24 @@ class ApplicationError(Exception):

class PyomoException(Exception):
"""
Exception class for other pyomo exceptions to inherit from,
allowing pyomo exceptions to be caught in a general way
Exception class for other Pyomo exceptions to inherit from,
allowing Pyomo exceptions to be caught in a general way
(e.g., in other applications that use Pyomo).
"""

pass


class DeferredImportError(ImportError):
"""This exception is raised when something attempts to access a module
that was imported by :py:func:`.attempt_import`, but the module
import failed.
"""

pass


class DeveloperError(PyomoException, NotImplementedError):
"""
Exception class used to throw errors that result from Pyomo
Expand All @@ -116,9 +156,11 @@ def __str__(self):
)


class InvalidValueError(PyomoException, ValueError):
class InfeasibleConstraintException(PyomoException):
"""
Exception class used for for value errors in compiled model representations
Exception class used by Pyomo transformations to indicate
that an infeasible constraint has been identified (e.g. in
the course of range reduction).
"""

pass
Expand All @@ -132,26 +174,9 @@ class IntervalException(PyomoException, ValueError):
pass


class InfeasibleConstraintException(PyomoException):
"""
Exception class used by Pyomo transformations to indicate
that an infeasible constraint has been identified (e.g. in
the course of range reduction).
class InvalidValueError(PyomoException, ValueError):
"""

pass


class NondifferentiableError(PyomoException, ValueError):
"""A Pyomo-specific ValueError raised for non-differentiable expressions"""

pass


class TempfileContextError(PyomoException, IndexError):
"""A Pyomo-specific IndexError raised when attempting to use the
TempfileManager when it does not have a currently active context.
Exception class used for value errors in compiled model representations
"""

pass
Expand All @@ -177,3 +202,18 @@ def __str__(self):
"pull requests are always welcome!",
exception=self,
)


class NondifferentiableError(PyomoException, ValueError):
"""A Pyomo-specific ValueError raised for non-differentiable expressions"""

pass


class TempfileContextError(PyomoException, IndexError):
"""A Pyomo-specific IndexError raised when attempting to use the
TempfileManager when it does not have a currently active context.
"""

pass

0 comments on commit abfedb9

Please sign in to comment.