Skip to content

Commit

Permalink
Trac #30616: Replace use of sage.misc.package.PackageNotFoundError
Browse files Browse the repository at this point in the history
…(2); lazy_import: Add keyword argument 'feature'

This helps with the modularization of sagelib.

We demonstrate its use by simplifying:
- `sage.groups.braid` (which depends on the optional library
`libbraiding` via `sage.libs.libbraiding`). Actually a standard package
- `sage.sat.solvers.cryptominisat`, `.picosat`
- `sage.matrix.matrix_space` (`meataxe`)
- `sage.graphs.graph` (`tdlib`, `mcqd`)

This simplification helps eliminate the use of
`sage.misc.package.PackageNotFoundError`.  See #30607.

URL: https://trac.sagemath.org/30616
Reported by: mkoeppe
Ticket author(s): Matthias Koeppe
Reviewer(s): David Coudert
  • Loading branch information
Release Manager committed Oct 4, 2020
2 parents 8a6a415 + e1f6624 commit 4e66cfe
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 83 deletions.
28 changes: 12 additions & 16 deletions src/sage/graphs/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,10 @@
from sage.misc.rest_index_of_methods import doc_index, gen_thematic_rest_table_index
from sage.graphs.views import EdgesView

from sage.misc.lazy_import import lazy_import
from sage.features import PythonModule
lazy_import('sage.graphs.mcqd', ['mcqd'],
feature=PythonModule('sage.graphs.mcqd', spkg='mcqd'))

class Graph(GenericGraph):
r"""
Expand Down Expand Up @@ -2691,10 +2695,11 @@ def treewidth(self, k=None, certificate=False, algorithm=None):
elif algorithm != "sage":
raise ValueError("'algorithm' must be equal to 'tdlib', 'sage', or None")

if algorithm is None and tdlib_found:
algorithm = 'tdlib'
else:
algorithm = 'sage'
if algorithm is None:
if tdlib_found:
algorithm = 'tdlib'
else:
algorithm = 'sage'

if k is not None and k < 0:
raise ValueError("k(={}) must be a nonnegative integer".format(k))
Expand All @@ -2717,8 +2722,9 @@ def treewidth(self, k=None, certificate=False, algorithm=None):
# TDLIB
if algorithm == 'tdlib':
if not tdlib_found:
from sage.misc.package import PackageNotFoundError
raise PackageNotFoundError("tdlib")
from sage.features import FeatureNotPresentError
raise FeatureNotPresentError(PythonModule('sage.graphs.graph_decompositions.tdlib',
spkg='tdlib'))

T = tdlib.treedecomposition_exact(g, -1 if k is None else k)
width = tdlib.get_width(T)
Expand Down Expand Up @@ -6410,11 +6416,6 @@ def clique_maximum(self, algorithm="Cliquer", solver=None, verbose=0):
elif algorithm == "MILP":
return self.complement().independent_set(algorithm=algorithm, solver=solver, verbosity=verbose)
elif algorithm == "mcqd":
try:
from sage.graphs.mcqd import mcqd
except ImportError:
from sage.misc.package import PackageNotFoundError
raise PackageNotFoundError("mcqd")
return mcqd(self)
else:
raise NotImplementedError("Only 'MILP', 'Cliquer' and 'mcqd' are supported.")
Expand Down Expand Up @@ -6513,11 +6514,6 @@ def clique_number(self, algorithm="Cliquer", cliques=None, solver=None, verbose=
elif algorithm == "MILP":
return len(self.complement().independent_set(algorithm=algorithm, solver=solver, verbosity=verbose))
elif algorithm == "mcqd":
try:
from sage.graphs.mcqd import mcqd
except ImportError:
from sage.misc.package import PackageNotFoundError
raise PackageNotFoundError("mcqd")
return len(mcqd(self))
else:
raise NotImplementedError("Only 'networkx' 'MILP' 'Cliquer' and 'mcqd' are supported.")
Expand Down
51 changes: 7 additions & 44 deletions src/sage/groups/braid.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
from sage.rings.integer import Integer
from sage.rings.integer_ring import IntegerRing
from sage.misc.lazy_attribute import lazy_attribute
from sage.misc.lazy_import import lazy_import
from sage.misc.cachefunc import cached_method
from sage.categories.groups import Groups
from sage.groups.free_group import FreeGroup, is_FreeGroup
Expand All @@ -80,7 +81,13 @@
from sage.groups.artin import FiniteTypeArtinGroup, FiniteTypeArtinGroupElement
from sage.misc.package import PackageNotFoundError
from sage.structure.richcmp import richcmp, rich_to_bool
from sage.features import PythonModule

lazy_import('sage.libs.braiding',
['rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor',
'leastcommonmultiple', 'conjugatingbraid', 'ultrasummitset',
'thurston_type', 'rigidity', 'sliding_circuits'],
feature=PythonModule('sage.libs.braiding', spkg='libbraiding'))

class Braid(FiniteTypeArtinGroupElement):
"""
Expand Down Expand Up @@ -1070,10 +1077,6 @@ def right_normal_form(self):
sage: b.right_normal_form()
(s1*s0, s0*s2, 1)
"""
try:
from sage.libs.braiding import rightnormalform
except ImportError:
raise PackageNotFoundError("libbraiding")
l = rightnormalform(self)
B = self.parent()
return tuple([B(b) for b in l[:-1]] + [B.delta() ** l[-1][0]])
Expand All @@ -1090,10 +1093,6 @@ def centralizer(self):
[s1*s0*s2*s1, s0*s2]
"""
try:
from sage.libs.braiding import centralizer
except ImportError:
raise PackageNotFoundError("libbraiding")
l = centralizer(self)
B = self.parent()
return [B._element_from_libbraiding(b) for b in l]
Expand All @@ -1113,10 +1112,6 @@ def super_summit_set(self):
s0^-1*s1^-1*s0^-2*s1^-1*s0*s1^3*s0]
"""
try:
from sage.libs.braiding import supersummitset
except ImportError:
raise PackageNotFoundError("libbraiding")
l = supersummitset(self)
B = self.parent()
return [B._element_from_libbraiding(b) for b in l]
Expand All @@ -1139,10 +1134,6 @@ def gcd(self, other):
sage: c.gcd(b)
s0^-1*s1^-1*s0^-2*s1^2*s0
"""
try:
from sage.libs.braiding import greatestcommondivisor
except ImportError:
raise PackageNotFoundError("libbraiding")
B = self.parent()
b = greatestcommondivisor(self, other)
return B._element_from_libbraiding(b)
Expand All @@ -1163,10 +1154,6 @@ def lcm(self, other):
sage: b.lcm(c)
(s0*s1)^2*s0
"""
try:
from sage.libs.braiding import leastcommonmultiple
except ImportError:
raise PackageNotFoundError("libbraiding")
B = self.parent()
b = leastcommonmultiple(self, other)
return B._element_from_libbraiding(b)
Expand All @@ -1193,10 +1180,6 @@ def conjugating_braid(self, other):
sage: d * a / d == c
False
"""
try:
from sage.libs.braiding import conjugatingbraid
except ImportError:
raise PackageNotFoundError("libbraiding")
l = conjugatingbraid(self, other)
if not l:
return None
Expand All @@ -1222,10 +1205,6 @@ def is_conjugated(self, other):
sage: c.is_conjugated(b)
False
"""
try:
from sage.libs.braiding import conjugatingbraid
except ImportError:
raise PackageNotFoundError("libbraiding")
l = conjugatingbraid(self, other)
return bool(l)

Expand Down Expand Up @@ -1254,10 +1233,6 @@ def ultra_summit_set(self):
s0^-1*s1^-1*s0^-2*s1^-1*s0^4*s1^2*s0,
s0^-1*s1^-1*s0^-2*s1^-1*s0^3*s1^2*s0^2]]
"""
try:
from sage.libs.braiding import ultrasummitset
except ImportError:
raise PackageNotFoundError("libbraiding")
uss = ultrasummitset(self)
B = self.parent()
return [[B._element_from_libbraiding(i) for i in s] for s in uss]
Expand All @@ -1283,10 +1258,6 @@ def thurston_type(self):
sage: c.thurston_type()
'periodic'
"""
try:
from sage.libs.braiding import thurston_type
except ImportError:
raise PackageNotFoundError("libbraiding")
return thurston_type(self)

def is_reducible(self):
Expand Down Expand Up @@ -1352,10 +1323,6 @@ def rigidity(self):
sage: b.rigidity()
0
"""
try:
from sage.libs.braiding import rigidity
except ImportError:
raise PackageNotFoundError("libbraiding")
return Integer(rigidity(self))

def sliding_circuits(self):
Expand Down Expand Up @@ -1388,10 +1355,6 @@ def sliding_circuits(self):
sage: b.sliding_circuits()
[[s0*s1*s0^2, (s0*s1)^2]]
"""
try:
from sage.libs.braiding import sliding_circuits
except ImportError:
raise PackageNotFoundError("libbraiding")
slc = sliding_circuits(self)
B = self.parent()
return [[B._element_from_libbraiding(i) for i in s] for s in slc]
Expand Down
13 changes: 6 additions & 7 deletions src/sage/matrix/matrix_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@
from sage.categories.fields import Fields
from sage.categories.enumerated_sets import EnumeratedSets

from sage.misc.lazy_import import lazy_import
from sage.features import PythonModule
lazy_import('sage.matrix.matrix_gfpn_dense', ['Matrix_gfpn_dense'],
feature=PythonModule('sage.matrix.matrix_gfpn_dense', spkg='meataxe'))

_Rings = Rings()
_Fields = Fields()

Expand Down Expand Up @@ -279,13 +284,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation):

if implementation == 'meataxe':
if R.is_field() and R.order() < 256:
try:
from . import matrix_gfpn_dense
except ImportError:
from sage.misc.package import PackageNotFoundError
raise PackageNotFoundError('meataxe')
else:
return matrix_gfpn_dense.Matrix_gfpn_dense
return Matrix_gfpn_dense
raise ValueError("'meataxe' matrix can only deal with finite fields of order < 256")

if implementation == 'numpy':
Expand Down
18 changes: 13 additions & 5 deletions src/sage/misc/lazy_import.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ import inspect
from . import sageinspect

from .lazy_import_cache import get_cache_file

from sage.features import FeatureNotPresentError

cdef inline obj(x):
if type(x) is LazyImport:
Expand Down Expand Up @@ -159,8 +159,10 @@ cdef class LazyImport(object):
cdef _namespace
cdef bint _at_startup
cdef _deprecation
cdef _feature

def __init__(self, module, name, as_name=None, at_startup=False, namespace=None, deprecation=None):
def __init__(self, module, name, as_name=None, at_startup=False, namespace=None,
deprecation=None, feature=None):
"""
EXAMPLES::
Expand All @@ -178,6 +180,7 @@ cdef class LazyImport(object):
self._namespace = namespace
self._at_startup = at_startup
self._deprecation = deprecation
self._feature = feature

cdef inline get_object(self):
"""
Expand Down Expand Up @@ -217,7 +220,12 @@ cdef class LazyImport(object):
raise RuntimeError(f"resolving lazy import {self._name} during startup")
elif self._at_startup and not startup_guard:
print('Option ``at_startup=True`` for lazy import {0} not needed anymore'.format(self._name))
self._object = getattr(__import__(self._module, {}, {}, [self._name]), self._name)
try:
self._object = getattr(__import__(self._module, {}, {}, [self._name]), self._name)
except ImportError as e:
if self._feature:
raise FeatureNotPresentError(self._feature, reason=f'Importing {self._name} failed: {e}')
raise
name = self._as_name
if self._deprecation is not None:
from sage.misc.superseded import deprecation
Expand Down Expand Up @@ -953,7 +961,7 @@ cdef class LazyImport(object):


def lazy_import(module, names, as_=None, *,
at_startup=False, namespace=None, deprecation=None):
at_startup=False, namespace=None, deprecation=None, feature=None):
"""
Create a lazy import object and inject it into the caller's global
namespace. For the purposes of introspection and calling, this is
Expand Down Expand Up @@ -1061,7 +1069,7 @@ def lazy_import(module, names, as_=None, *,
names[ix:ix+1] = all
as_[ix:ix+1] = all
for name, alias in zip(names, as_):
namespace[alias] = LazyImport(module, name, alias, at_startup, namespace, deprecation)
namespace[alias] = LazyImport(module, name, alias, at_startup, namespace, deprecation, feature)


star_imports = None
Expand Down
9 changes: 4 additions & 5 deletions src/sage/sat/solvers/cryptominisat.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@

from .satsolver import SatSolver

from sage.misc.lazy_import import lazy_import
from sage.features import PythonModule
lazy_import('pycryptosat', ['Solver'],
feature=PythonModule('pycryptosat', spkg='cryptominisat'))

class CryptoMiniSat(SatSolver):
r"""
Expand Down Expand Up @@ -65,11 +69,6 @@ def __init__(self, verbosity=0, confl_limit=None, threads=None):
if confl_limit is None:
from sys import maxsize
confl_limit = maxsize
try:
from pycryptosat import Solver
except ImportError:
from sage.misc.package import PackageNotFoundError
raise PackageNotFoundError("cryptominisat")
self._solver = Solver(verbose=int(verbosity), confl_limit=int(confl_limit), threads=int(threads))
self._nvars = 0
self._clauses = []
Expand Down
12 changes: 6 additions & 6 deletions src/sage/sat/solvers/picosat.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@

from .satsolver import SatSolver

from sage.misc.lazy_import import lazy_import
from sage.features import PythonModule
lazy_import('pycosat', ['solve'],
feature=PythonModule('pycosat', spkg='pycosat'))

class PicoSAT(SatSolver):
r"""
PicoSAT Solver.
Expand Down Expand Up @@ -55,12 +60,7 @@ def __init__(self, verbosity=0, prop_limit=0):
self._prop_limit = 0
else:
self._prop_limit = int(prop_limit)
try:
import pycosat
except ImportError:
from sage.misc.package import PackageNotFoundError
raise PackageNotFoundError("pycosat")
self._solve = pycosat.solve
self._solve = solve
self._nvars = 0
self._clauses = []

Expand Down

0 comments on commit 4e66cfe

Please sign in to comment.