diff --git a/conftest.py b/conftest.py index 5307d7f6233..a42ac87c67d 100644 --- a/conftest.py +++ b/conftest.py @@ -32,7 +32,6 @@ ) from sage.doctest.parsing import SageDocTestParser, SageOutputChecker - class SageDoctestModule(DoctestModule): """ This is essentially a copy of `DoctestModule` from @@ -125,15 +124,26 @@ def _find( checker=SageOutputChecker(), continue_on_failure=_get_continue_on_failure(self.config), ) + # Monkey patch exception reporting to ignore FeatureNotPresentError + old_report_unexpected_exception = runner.report_unexpected_exception + def _report_unexpected_exception(self, test, example, exc_info): + if isinstance(exc_info[1], FeatureNotPresentError): + # Ignore FeatureNotPresentError + # (it's not an error in the doctest) + return + return old_report_unexpected_exception(self, test, example, exc_info) + runner.report_unexpected_exception = _report_unexpected_exception try: + print(f"Collecting doctests from { self.path }: { module }") for test in finder.find(module, module.__name__): + print(test) if test.examples: # skip empty doctests yield DoctestItem.from_parent( self, name=test.name, runner=runner, dtest=test ) except FeatureNotPresentError as exception: pytest.skip( - f"unable to import module { self.path } due to missing feature { exception.feature.name }" + f"unable to import module { self.path } due to { exception }" ) except ModuleNotFoundError as exception: # TODO: Remove this once all optional things are using Features @@ -175,6 +185,7 @@ def pytest_collect_file( # We don't allow pytests to be defined in Cython files. # Normally, Cython files are filtered out already by pytest and we only # hit this here if someone explicitly runs `pytest some_file.pyx`. + #return SageDoctestModule.from_parent(parent, path=file_path) return IgnoreCollector.from_parent(parent) elif file_path.suffix == ".py": if parent.config.option.doctest: diff --git a/src/sage/algebras/fusion_rings/meson.build b/src/sage/algebras/fusion_rings/meson.build index 221cce6146e..692e046cf71 100644 --- a/src/sage/algebras/fusion_rings/meson.build +++ b/src/sage/algebras/fusion_rings/meson.build @@ -35,6 +35,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, cysignals, gmp, singular] py.extension_module( name, sources: pyx, @@ -42,7 +43,25 @@ foreach name, pyx : extension_data_cpp install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython, inc_ntl, inc_numpy, inc_rings], - dependencies: [py_dep, cysignals, gmp, singular], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'algebras/fusion_rings', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/algebras/letterplace/meson.build b/src/sage/algebras/letterplace/meson.build index 3e429eb420a..8f3cef0ffbc 100644 --- a/src/sage/algebras/letterplace/meson.build +++ b/src/sage/algebras/letterplace/meson.build @@ -15,6 +15,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, gmp, singular] py.extension_module( name, sources: pyx, @@ -22,7 +23,25 @@ foreach name, pyx : extension_data_cpp install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython, inc_rings], - dependencies: [py_dep, gmp, singular], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'algebras/letterplace', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/algebras/quatalg/meson.build b/src/sage/algebras/quatalg/meson.build index 25c4adfc46c..37627e67218 100644 --- a/src/sage/algebras/quatalg/meson.build +++ b/src/sage/algebras/quatalg/meson.build @@ -12,6 +12,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, flint, gmp, m, ntl] py.extension_module( name, sources: pyx, @@ -19,7 +20,25 @@ foreach name, pyx : extension_data_cpp install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython, inc_ext, inc_flint, inc_ntl, inc_rings], - dependencies: [py_dep, flint, gmp, m, ntl], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'algebras/quatalg', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/calculus/meson.build b/src/sage/calculus/meson.build index 3bedeb2220a..36f021ec132 100644 --- a/src/sage/calculus/meson.build +++ b/src/sage/calculus/meson.build @@ -25,14 +25,33 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, gmp, gsl, interpreters_dep] py.extension_module( name, sources: pyx, subdir: 'sage/calculus', install: true, include_directories: [inc_numpy], - dependencies: [py_dep, cysignals, gmp, gsl, interpreters_dep], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'calculus', + install: true, + copy: true, + ) + endif endforeach subdir('transforms') diff --git a/src/sage/calculus/transforms/meson.build b/src/sage/calculus/transforms/meson.build index 11ffa9f8ec1..3a6147bc0c4 100644 --- a/src/sage/calculus/transforms/meson.build +++ b/src/sage/calculus/transforms/meson.build @@ -10,13 +10,32 @@ py.install_sources( extension_data = {'dwt' : files('dwt.pyx'), 'fft' : files('fft.pyx')} foreach name, pyx : extension_data + deps = [py_dep, cysignals, gmp, gsl] py.extension_module( name, sources: pyx, subdir: 'sage/calculus/transforms', install: true, include_directories: [inc_gsl], - dependencies: [py_dep, cysignals, gmp, gsl], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'calculus/transforms', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/coding/codecan/meson.build b/src/sage/coding/codecan/meson.build index 1ccaca09b2a..c67b2710a4c 100644 --- a/src/sage/coding/codecan/meson.build +++ b/src/sage/coding/codecan/meson.build @@ -11,6 +11,7 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, gap, gmp] py.extension_module( name, sources: pyx, @@ -22,7 +23,25 @@ foreach name, pyx : extension_data inc_partn_ref2, inc_rings, ], - dependencies: [py_dep, cysignals, gap, gmp], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'coding/codecan', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/combinat/meson.build b/src/sage/combinat/meson.build index 441caadca17..3a652716463 100644 --- a/src/sage/combinat/meson.build +++ b/src/sage/combinat/meson.build @@ -159,6 +159,24 @@ foreach name, pyx : extension_data include_directories: [inc_cpython, inc_data_structures, inc_rings], dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'combinat', + install: true, + copy: true, + ) + endif endforeach install_subdir('chas', install_dir: sage_install_dir / 'combinat') diff --git a/src/sage/combinat/posets/meson.build b/src/sage/combinat/posets/meson.build index 9832967b4ff..29d705208df 100644 --- a/src/sage/combinat/posets/meson.build +++ b/src/sage/combinat/posets/meson.build @@ -23,13 +23,32 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, flint, gmp] py.extension_module( name, sources: pyx, subdir: 'sage/combinat/posets', install: true, include_directories: [inc_cpython, inc_ext, inc_flint, inc_rings], - dependencies: [py_dep, cysignals, flint, gmp], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'combinat/posets', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/combinat/root_system/meson.build b/src/sage/combinat/root_system/meson.build index 629c67bcdd6..e85d343c0e8 100644 --- a/src/sage/combinat/root_system/meson.build +++ b/src/sage/combinat/root_system/meson.build @@ -78,5 +78,23 @@ foreach name, pyx : extension_data include_directories: [inc_cpython, inc_rings], dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'combinat/root_system', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/data_structures/meson.build b/src/sage/data_structures/meson.build index 8c100328378..58eba2a47c5 100644 --- a/src/sage/data_structures/meson.build +++ b/src/sage/data_structures/meson.build @@ -27,6 +27,7 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, flint, gmp] py.extension_module( name, sources: pyx, @@ -38,13 +39,28 @@ foreach name, pyx : extension_data inc_flint, inc_rings, ], - dependencies: [py_dep, cysignals, flint, gmp], + dependencies: deps, ) + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'data_structures', + install: true, + copy: true, + ) + endif endforeach -extension_data_cpp = { - 'pairing_heap' : files('pairing_heap.pyx'), -} +extension_data_cpp = {'pairing_heap' : files('pairing_heap.pyx')} foreach name, pyx : extension_data_cpp py.extension_module( diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index ac4a0bcd97f..e7ed24dd619 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -435,7 +435,7 @@ class FeatureNotPresentError(RuntimeError): ... FeatureNotPresentError: missing is not available. """ - def __init__(self, feature, reason=None, resolution=None): + def __init__(self, feature: Feature | None = None, reason: str | None=None, resolution: str | None =None): self.feature = feature self.reason = reason self._resolution = resolution @@ -459,12 +459,13 @@ def __str__(self): FeatureNotPresentError: gap_package_gapZuHoh8Uu is not available. `LoadPackage("gapZuHoh8Uu")` evaluated to `fail` in GAP. """ - lines = ["{feature} is not available.".format(feature=self.feature.name)] + lines = [] + if self.feature: + lines.append(f"{self.feature.name} is not available.") if self.reason: lines.append(self.reason) - resolution = self.resolution - if resolution: - lines.append(str(resolution)) + if self._resolution: + lines.append(str(self._resolution)) return "\n".join(lines) @@ -963,8 +964,8 @@ def __init__(self, name, **kwds): def _is_present(self): r""" - Return whether the module can be imported. This is determined by - actually importing it. + Return whether the module can be found. It is not tested whether the + module can be imported or otherwise is functional. EXAMPLES:: @@ -974,9 +975,9 @@ def _is_present(self): sage: PythonModule("_no_such_module_").is_present() FeatureTestResult('_no_such_module_', False) """ - import importlib + import importlib.util try: - importlib.import_module(self.name) + importlib.util.find_spec(self.name) except ImportError as exception: - return FeatureTestResult(self, False, reason=f"Failed to import `{self.name}`: {exception}") + return FeatureTestResult(self, False, reason=f"Failed to find `{self.name}`: {exception}") return FeatureTestResult(self, True, reason=f"Successfully imported `{self.name}`.") diff --git a/src/sage/features/mock.py b/src/sage/features/mock.py new file mode 100644 index 00000000000..dcd682c37bd --- /dev/null +++ b/src/sage/features/mock.py @@ -0,0 +1,220 @@ +from collections.abc import Iterable +from typing import Any + +from sage.features import FeatureNotPresentError + +class MockConstructor(type): + _name: str + + def __new__(cls, name: str, bases: tuple[type, ...], attrs: dict[str, Any], module: str | None = None): + print(f"Constructor: __new__") + attrs["_name"] = name + attrs["_module"] = module + return super().__new__(cls, name, bases, attrs) + + # if len(args) == 3 and isinstance(args[1], tuple): + # super().__new__(cls, *args) + # return cls + + # def __init__(self, *args, name: str, **kwargs): + # self._name = name + + # def __getattr__(self, attr: str) -> Any: + # # For debugging: + # print(f"__getattr__ {attr}") + # return mock(f"{self._name}.{attr}") + +class MockInstance:#(metaclass=Mock): + _name: str + _module: str + #__pyx_vtable__ = 1 + + def __getattr__(self, attr: str) -> Any: + # For debugging: + print(f"__getattr__ instance {attr}") + if attr in ("_name", "_module"): + raise NotImplementedError(attr) + # if attr == '__pyx_vtable__': + # return 1 + + return mock(self._module, f"{self._name}.{attr}") + +# class Wrapper(type): +# _key: str + +# def __new__(cls, *args, **kwargs): +# # For debugging: +# print(f"__new__ {len(args)}") +# # return super().__new__(cls) +# if len(args) == 3 and isinstance(args[1], tuple): +# super().__new__(cls, *args) +# #superclass = args[1][-1].__class__ +# #print(f"__new__ {args[0], superclass.__display_name__}") +# #if superclass is cls: +# # return super().__new__( +# # args[0], +# # superclass.__display_name__, +# # superclass=superclass, +# # attributes=args[2]) +# #cls._key = args[0] +# return cls +# #raise FeatureNotPresentError( +# # reason=f"A dependency of the package {__name__} is not available, trying to access {args[0]}" +# #) + +# def __init__(self, *args, **kwargs): +# print(f"__init__") +# #self._key = name + +# def raise_error(self): +# raise FeatureNotPresentError( +# reason=f"A dependency of the package {__name__} is not available, trying to access {self._key}" +# ) + +# def __basicsize__(self): +# print(f"__basicsize__") +# self.raise_error() + + def __call__(self, *args, **kwargs): + # For debugging: + print(f"__call__{self._name}") + #for arg in args: + # for subarg in arg: + # print(type(subarg)) + self.raise_error() + + # def __mro_entries__(self, bases): + # """ + # In case someone tries to inherit from this class, we substitute the bases with + # a Wrapper. + # See https://docs.python.org/3/reference/datamodel.html#object.__mro_entries__ + # """ + # return (self.__class__, ) + +# def __getattribute__(self, attr: str) -> Any: +# if attr in ('_key', 'raise_error'): +# return super().__getattribute__(attr) +# # For debugging: +# print(f"__getattr__ {attr}") +# return self + + def __repr__(self): + print(f"__repr__") + return f"" + #return super().__repr__() + #self.raise_error() + +# def __eq__(self, value: object) -> bool: +# print(f"__eq__ {value}") +# return super().__eq__(value) + +# def __subclasscheck__(self, subclass: type) -> bool: +# print(f"__subclasscheck__ {subclass}") +# return True + +# def __instancecheck__(self, instance: object) -> bool: +# print(f"__instancecheck__ {instance}") +# return True + +# @classmethod +# def __subclasshook__(cls, subclass: type) -> bool: +# print(f"__subclasshook__ {subclass}") +# return True + +# def __init_subclass__(cls, **kwargs): +# print(f"__init_subclass__ {kwargs}") +# return super().__init_subclass__(**kwargs) + + +# class Mock:#(metaclass=Wrapper): +# _key: str + +# def __init__(self, *args, **kwargs): +# print(f"__init__") +# self._key = args[0] + + def raise_error(self): + raise FeatureNotPresentError( + reason=f"A dependency of the package '{self._module}' is not available, trying to access '{self._name}'" + ) + +# def __basicsize__(self): +# print(f"__basicsize__") +# self.raise_error() + +# def __call__(self, *args, **kwargs): +# # For debugging: +# print(f"__call__{self._key}") +# for arg in args: +# for subarg in arg: +# print(type(subarg)) +# self.raise_error() + + def __mro_entries__(self, bases): + """ + In case someone tries to inherit from this class, we substitute the bases with + a Wrapper. + See https://docs.python.org/3/reference/datamodel.html#object.__mro_entries__ + """ + print(f"__mro_entries__ {bases}") + #MockCls = MockConstructor(self._name, (MockInstance, ), {}, module=self._module) + #return (MockCls, ) + MockCls = self.__class__ + MockCls._module = self._module + MockCls._name = self._name + return (MockCls, ) + +# def __getattribute__(self, attr: str) -> Any: +# if attr in ('_key', 'raise_error'): +# return super().__getattribute__(attr) +# # For debugging: +# print(f"__getattr__ {attr}") +# return self + +# def __repr__(self): +# print(f"__repr__") +# return self._key +# #return super().__repr__() +# #self.raise_error() + +# def __eq__(self, value: object) -> bool: +# print(f"__eq__ {value}") +# return super().__eq__(value) + +# def __subclasscheck__(self, subclass: type) -> bool: +# print(f"__subclasscheck__ {subclass}") +# return True + +# def __instancecheck__(self, instance: object) -> bool: +# print(f"__instancecheck__ {instance}") +# return True + +# @classmethod +# def __subclasshook__(cls, subclass: type) -> bool: +# print(f"__subclasshook__ {subclass}") +# return True + +# def __init_subclass__(cls, **kwargs): +# print(f"__init_subclass__ {kwargs}") +# return super().__init_subclass__(**kwargs) + + +def mock(module: str, name: str) -> MockInstance: + r""" + Return a mock object. + + EXAMPLES:: + + sage: from sage.features.mock import mock + sage: mock('foo') + + """ + print(f"mock {module}.{name}") + mock = MockInstance() + mock._module = module + mock._name = name + return mock + #MockCls = MockConstructor(name, (MockInstance, ), {}, module=module) + #return MockCls() + #return #MockInstance(module, name) + #return Mock.__new__(MockInstance, (), {}) diff --git a/src/sage/features/mock_test.py b/src/sage/features/mock_test.py new file mode 100644 index 00000000000..40f99ec7903 --- /dev/null +++ b/src/sage/features/mock_test.py @@ -0,0 +1,68 @@ +import pytest + +from sage.features import FeatureNotPresentError +from sage.features.mock import MockInstance, mock + + +def test_mock_creation(): + m = mock('module', 'foo') + assert isinstance(m, MockInstance) + assert m._name == 'foo' + assert m._module == 'module' + +def test_mock_repr_returns_name(): + m = mock('module', 'foo') + assert repr(m) == "" + +def test_mock_call_raises_exception(): + m = mock('module', 'foo') + with pytest.raises(FeatureNotPresentError): + m() + +def test_mock_call_function_raises_exception(): + m = mock('module', 'foo') + with pytest.raises(FeatureNotPresentError): + m.function() # type: ignore + +def test_mock_get_attribute_returns_another_mock(): + m = mock('module', 'foo') + attribute = m.bar # type: ignore + assert isinstance(attribute, MockInstance) + assert attribute._name == 'foo.bar' + assert attribute._module == 'module' + +def test_can_inherit_from_mock_without_raising_exception(): + m = mock('module', 'foo') + class MyMock(m): # type: ignore + pass + with pytest.raises(FeatureNotPresentError): + MyMock().bar() + +def test_can_inherit_from_mock_with_other_bases(): + m = mock('module', 'foo') + class Bar: + pass + class MyMock(m, Bar): # type: ignore + pass + with pytest.raises(FeatureNotPresentError): + MyMock().bar() + +def test_can_inherit_from_mock_with_other_metaclass(): + m = mock('module', 'foo') + class MyMeta(type): + def __new__(cls, name, bases, dct): + return super().__new__(cls, name, bases, dct) + class Bar(metaclass=MyMeta): + pass + class MyMock(m, Bar): # type: ignore + pass + with pytest.raises(FeatureNotPresentError): + MyMock().bar() + +# def test_can_inherit_from_mock_and_algebra_element(): +# m = mock('module', 'foo') +# from sage.structure.element import AlgebraElement +# class MyMock(m, AlgebraElement): +# pass +# with pytest.raises(FeatureNotPresentError): +# MyMock() diff --git a/src/sage/features/not_available.py.in b/src/sage/features/not_available.py.in new file mode 100644 index 00000000000..37313a6dcab --- /dev/null +++ b/src/sage/features/not_available.py.in @@ -0,0 +1,14 @@ +# This file will be installed whenever the corresponding Cython extension module +# cannot be built due to missing dependencies. It provides a mock object that allows to import +# arbitrary attributes without raising an ImportError. However, when actually invoking +# any function on the mock a FeatureNotPresentError is raised. + +from sage.features.mock import mock + +def __getattr__(key: str): + if key == '__path__': + # This is a special attribute that Python looks for when importing a package. + # We raise AttributeError to prevent Python from querying every attribute twice. + # https://stackoverflow.com/questions/56786604/import-modules-that-dont-exist-yet + raise AttributeError + return mock(__name__, key) diff --git a/src/sage/geometry/meson.build b/src/sage/geometry/meson.build index 3b48404564d..7bb9ae89a8b 100644 --- a/src/sage/geometry/meson.build +++ b/src/sage/geometry/meson.build @@ -46,6 +46,24 @@ foreach name, pyx : extension_data include_directories: [inc_cpython, inc_ext, inc_flint, inc_rings], dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'geometry', + install: true, + copy: true, + ) + endif endforeach install_subdir('hyperbolic_space', install_dir: sage_install_dir / 'geometry') diff --git a/src/sage/graphs/graph_decompositions/meson.build b/src/sage/graphs/graph_decompositions/meson.build index 913c682ebac..3324c751476 100644 --- a/src/sage/graphs/graph_decompositions/meson.build +++ b/src/sage/graphs/graph_decompositions/meson.build @@ -31,14 +31,33 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, gmp, rw] py.extension_module( name, sources: pyx, subdir: 'sage/graphs/graph_decompositions', install: true, include_directories: [inc_cpython, inc_data_structures], - dependencies: [py_dep, cysignals, gmp, rw], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'graphs/graph_decompositions', + install: true, + copy: true, + ) + endif endforeach extension_data_cpp = { @@ -48,6 +67,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, cysignals, gmp, rw] py.extension_module( name, sources: pyx, @@ -55,10 +75,29 @@ foreach name, pyx : extension_data_cpp install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython, inc_data_structures], - dependencies: [py_dep, cysignals, gmp, rw], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'graphs/graph_decompositions', + install: true, + copy: true, + ) + endif endforeach +deps = [py_dep, cysignals, tdlib] py.extension_module( 'tdlib', sources: 'tdlib.pyx', @@ -66,6 +105,22 @@ py.extension_module( install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython, inc_data_structures], - dependencies: [py_dep, cysignals, tdlib], + dependencies: deps, ) - +all_deps_found = true +foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif +endforeach +if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'graphs/graph_decompositions', + install: true, + copy: true, + ) +endif diff --git a/src/sage/graphs/meson.build b/src/sage/graphs/meson.build index 842501734e5..82528608e6c 100644 --- a/src/sage/graphs/meson.build +++ b/src/sage/graphs/meson.build @@ -81,6 +81,7 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, cliquer, flint, gmp, planarity] py.extension_module( name, sources: pyx, @@ -92,8 +93,26 @@ foreach name, pyx : extension_data inc_flint, inc_rings, ], - dependencies: [py_dep, cysignals, cliquer, flint, gmp, planarity], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'graphs', + install: true, + copy: true, + ) + endif endforeach extension_data_cpp = { @@ -104,6 +123,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, cysignals, flint, gmp, planarity] py.extension_module( name, sources: pyx, @@ -116,10 +136,29 @@ foreach name, pyx : extension_data_cpp inc_flint, inc_rings, ], - dependencies: [py_dep, cysignals, flint, gmp, planarity], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'graphs', + install: true, + copy: true, + ) + endif endforeach +deps = [py_dep, cysignals, bliss] py.extension_module( 'bliss', sources: files('bliss.pyx'), @@ -127,9 +166,27 @@ py.extension_module( install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython, inc_data_structures, inc_flint, inc_rings], - dependencies: [py_dep, cysignals, bliss], + dependencies: deps, ) +all_deps_found = true +foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif +endforeach +if not all_deps_found + configure_file( + input: not_available, + output: 'bliss.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'graphs', + install: true, + copy: true, + ) +endif +deps = [py_dep, cysignals, mcqd] py.extension_module( 'mcqd', sources: files('mcqd.pyx'), @@ -137,8 +194,25 @@ py.extension_module( install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython, inc_data_structures, inc_flint, inc_rings], - dependencies: [py_dep, cysignals, mcqd], + dependencies: deps, ) +all_deps_found = true +foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif +endforeach +if not all_deps_found + configure_file( + input: not_available, + output: 'mcqd.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'graphs', + install: true, + copy: true, + ) +endif subdir('base') subdir('generators') diff --git a/src/sage/groups/matrix_gps/meson.build b/src/sage/groups/matrix_gps/meson.build index 77c70adf7fa..6c5734bb0d6 100644 --- a/src/sage/groups/matrix_gps/meson.build +++ b/src/sage/groups/matrix_gps/meson.build @@ -47,5 +47,23 @@ foreach name, pyx : extension_data include_directories: [inc_cpython], dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'groups/matrix_gps', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/groups/meson.build b/src/sage/groups/meson.build index 37ba1028d5e..a80c70bd605 100644 --- a/src/sage/groups/meson.build +++ b/src/sage/groups/meson.build @@ -50,6 +50,24 @@ foreach name, pyx : extension_data include_directories: [inc_cpython], dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'groups', + install: true, + copy: true, + ) + endif endforeach install_subdir('abelian_gps', install_dir: sage_install_dir / 'groups') diff --git a/src/sage/groups/perm_gps/meson.build b/src/sage/groups/perm_gps/meson.build index 6ad30d99fe2..8dedf696286 100644 --- a/src/sage/groups/perm_gps/meson.build +++ b/src/sage/groups/perm_gps/meson.build @@ -15,14 +15,33 @@ py.install_sources( extension_data = {'permgroup_element' : files('permgroup_element.pyx')} foreach name, pyx : extension_data + deps = [py_dep, cysignals, gap, gmp] py.extension_module( name, sources: pyx, subdir: 'sage/groups/perm_gps', install: true, include_directories: [inc_cpython, inc_ext, inc_rings], - dependencies: [py_dep, cysignals, gap, gmp], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'groups/perm_gps', + install: true, + copy: true, + ) + endif endforeach subdir('partn_ref') diff --git a/src/sage/groups/perm_gps/partn_ref2/meson.build b/src/sage/groups/perm_gps/partn_ref2/meson.build index 69b9bee042d..5578bf3fc09 100644 --- a/src/sage/groups/perm_gps/partn_ref2/meson.build +++ b/src/sage/groups/perm_gps/partn_ref2/meson.build @@ -8,13 +8,32 @@ py.install_sources( extension_data = {'refinement_generic' : files('refinement_generic.pyx')} foreach name, pyx : extension_data + deps = [py_dep, cysignals, gmp, gap] py.extension_module( name, sources: pyx, subdir: 'sage/groups/perm_gps/partn_ref2', install: true, include_directories: [inc_cpython, inc_data_structures, inc_partn_ref2], - dependencies: [py_dep, cysignals, gmp, gap], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'groups/perm_gps/partn_ref2', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index 59d01f4493d..bf9b3b76856 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -342,6 +342,8 @@ import shlex import time +from sage.features import FeatureNotPresentError + from .expect import Expect, ExpectElement, FunctionElement, ExpectFunction import sage.interfaces.abc @@ -2450,7 +2452,10 @@ def get_docstring(name, prefix=False, code=False): return result -singular = Singular() +try: + singular = Singular() +except FeatureNotPresentError: + singular = None def reduce_load_Singular(): diff --git a/src/sage/lfunctions/meson.build b/src/sage/lfunctions/meson.build index 24e2f156f5e..3c89af63989 100644 --- a/src/sage/lfunctions/meson.build +++ b/src/sage/lfunctions/meson.build @@ -11,13 +11,32 @@ py.install_sources( extension_data = {'zero_sums' : files('zero_sums.pyx')} foreach name, pyx : extension_data + deps = [py_dep, flint, gmp] py.extension_module( name, sources: pyx, subdir: 'sage/lfunctions', install: true, include_directories: [inc_flint], - dependencies: [py_dep, flint, gmp], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'lfunctions', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/libs/arb/meson.build b/src/sage/libs/arb/meson.build index aa98fb8ff3a..5714eec75e4 100644 --- a/src/sage/libs/arb/meson.build +++ b/src/sage/libs/arb/meson.build @@ -21,13 +21,32 @@ py.install_sources( extension_data = {'arith' : files('arith.pyx')} foreach name, pyx : extension_data + deps = [py_dep, flint, gmp, mpfr] py.extension_module( name, sources: pyx, subdir: 'sage/libs/arb', install: true, include_directories: [inc_cpython, inc_flint, inc_rings], - dependencies: [py_dep, flint, gmp, mpfr], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs/arb', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/libs/coxeter3/meson.build b/src/sage/libs/coxeter3/meson.build index ee51998f27d..8ae975f159c 100644 --- a/src/sage/libs/coxeter3/meson.build +++ b/src/sage/libs/coxeter3/meson.build @@ -11,6 +11,7 @@ py.install_sources( extension_data_cpp = {'coxeter': files('coxeter.pyx')} foreach name, pyx : extension_data_cpp + deps = [py_dep, cysignals, coxeter3] py.extension_module( name, sources: pyx, @@ -18,6 +19,24 @@ foreach name, pyx : extension_data_cpp install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython], - dependencies: [py_dep, cysignals, coxeter3], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs/coxeter3', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/libs/eclib/meson.build b/src/sage/libs/eclib/meson.build index dd6ecc3f581..7db45ac9018 100644 --- a/src/sage/libs/eclib/meson.build +++ b/src/sage/libs/eclib/meson.build @@ -18,6 +18,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, cysignals, ec, flint, gmp] py.extension_module( name, sources: pyx, @@ -25,7 +26,25 @@ foreach name, pyx : extension_data_cpp install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython, inc_ext, inc_flint, inc_ntl, inc_rings], - dependencies: [py_dep, cysignals, ec, flint, gmp], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs/eclib', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/libs/flint/meson.build b/src/sage/libs/flint/meson.build index fe12b28b5f7..dcc74ce2b36 100644 --- a/src/sage/libs/flint/meson.build +++ b/src/sage/libs/flint/meson.build @@ -165,13 +165,32 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, flint, gmp, mpfr] py.extension_module( name, sources: pyx, subdir: 'sage/libs/flint', install: true, include_directories: [inc_cpython, inc_flint, inc_rings], - dependencies: [py_dep, cysignals, flint, gmp, mpfr], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs/flint', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/libs/gap/meson.build b/src/sage/libs/gap/meson.build index def07898f4c..b92336fd09c 100644 --- a/src/sage/libs/gap/meson.build +++ b/src/sage/libs/gap/meson.build @@ -27,13 +27,32 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, gap, gmp] py.extension_module( name, sources: pyx, subdir: 'sage/libs/gap', install: true, include_directories: [inc_cpython, inc_rings], - dependencies: [py_dep, cysignals, gap, gmp], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs/gap', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/libs/giac/meson.build b/src/sage/libs/giac/meson.build index 6dda5a6c8a7..f519c968cc1 100644 --- a/src/sage/libs/giac/meson.build +++ b/src/sage/libs/giac/meson.build @@ -5,6 +5,7 @@ py.install_sources('__init__.py', 'giac.pxd', 'misc.h', subdir: 'sage/libs/giac' extension_data_cpp = {'giac': files('giac.pyx')} foreach name, pyx : extension_data_cpp + deps = [py_dep, cysignals, giac, gmp] py.extension_module( name, sources: pyx, @@ -12,6 +13,24 @@ foreach name, pyx : extension_data_cpp install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython, inc_ext, inc_rings], - dependencies: [py_dep, cysignals, giac, gmp], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs/giac', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/libs/gsl/meson.build b/src/sage/libs/gsl/meson.build index ea5eac5e93a..75fa59cfc61 100644 --- a/src/sage/libs/gsl/meson.build +++ b/src/sage/libs/gsl/meson.build @@ -70,13 +70,32 @@ py.install_sources( extension_data = {'array' : files('array.pyx')} foreach name, pyx : extension_data + deps = [py_dep, cysignals, gmp, gsl] py.extension_module( name, sources: pyx, subdir: 'sage/libs/gsl', install: true, include_directories: [inc_gsl], - dependencies: [py_dep, cysignals, gmp, gsl], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs/gsl', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/libs/lcalc/meson.build b/src/sage/libs/lcalc/meson.build index aa6d9296948..a6ad2db95e1 100644 --- a/src/sage/libs/lcalc/meson.build +++ b/src/sage/libs/lcalc/meson.build @@ -10,6 +10,7 @@ py.install_sources( extension_data_cpp = {'lcalc_Lfunction': files('lcalc_Lfunction.pyx')} foreach name, pyx : extension_data_cpp + deps = [py_dep, cypari2, cysignals, gmp, lcalc, m, mpfr, ntl] py.extension_module( name, sources: pyx, @@ -17,7 +18,25 @@ foreach name, pyx : extension_data_cpp install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython, inc_rings], - dependencies: [py_dep, cypari2, cysignals, gmp, lcalc, m, mpfr, ntl], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs/lcalc', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/libs/linbox/meson.build b/src/sage/libs/linbox/meson.build index 252a6ae0f9e..45569638d99 100644 --- a/src/sage/libs/linbox/meson.build +++ b/src/sage/libs/linbox/meson.build @@ -13,6 +13,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, blas, flint, fplll, givaro, gmp, gmpxx, linbox] py.extension_module( name, sources: pyx, @@ -20,7 +21,25 @@ foreach name, pyx : extension_data_cpp install: true, override_options: ['cython_language=cpp'], include_directories: [inc_flint], - dependencies: [py_dep, blas, flint, fplll, givaro, gmp, gmpxx, linbox], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs/linbox', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/libs/meson.build b/src/sage/libs/meson.build index 53470399d46..eb5f9e527b6 100644 --- a/src/sage/libs/meson.build +++ b/src/sage/libs/meson.build @@ -52,11 +52,30 @@ foreach name, pyx : extension_data include_directories: [inc_cpython, inc_rings], dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs', + install: true, + copy: true, + ) + endif endforeach extension_data_cpp = {'braiding': files('braiding.pyx')} foreach name, pyx : extension_data_cpp + deps = dependencies py.extension_module( name, sources: pyx, @@ -66,6 +85,24 @@ foreach name, pyx : extension_data_cpp include_directories: [inc_cpython, inc_rings], dependencies: dependencies, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs', + install: true, + copy: true, + ) + endif endforeach subdir('arb') diff --git a/src/sage/libs/mpmath/meson.build b/src/sage/libs/mpmath/meson.build index a197516f9f1..ba295ed00cd 100644 --- a/src/sage/libs/mpmath/meson.build +++ b/src/sage/libs/mpmath/meson.build @@ -15,13 +15,32 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, gmp, mpfr] py.extension_module( name, sources: pyx, subdir: 'sage/libs/mpmath', install: true, include_directories: [inc_cpython, inc_ext, inc_rings], - dependencies: [py_dep, cysignals, gmp, mpfr], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs/mpmath', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/libs/ntl/__init__.py b/src/sage/libs/ntl/__init__.py index 0ab0a2c43e7..0dfd674687a 100644 --- a/src/sage/libs/ntl/__init__.py +++ b/src/sage/libs/ntl/__init__.py @@ -1,3 +1,7 @@ +from sage.features import FeatureNotPresentError from sage.libs.ntl.error import setup_NTL_error_callback -setup_NTL_error_callback() +try: + setup_NTL_error_callback() +except FeatureNotPresentError: + pass diff --git a/src/sage/libs/ntl/meson.build b/src/sage/libs/ntl/meson.build index 7f78db280fe..14f05f9e00e 100644 --- a/src/sage/libs/ntl/meson.build +++ b/src/sage/libs/ntl/meson.build @@ -71,6 +71,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, cysignals, gmp, m, ntl] py.extension_module( name, sources: pyx, @@ -84,7 +85,25 @@ foreach name, pyx : extension_data_cpp inc_rings, inc_rings_finite, ], - dependencies: [py_dep, cysignals, gmp, m, ntl], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs/ntl', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/libs/pari/meson.build b/src/sage/libs/pari/meson.build index 5952060267c..1ad7d210553 100644 --- a/src/sage/libs/pari/meson.build +++ b/src/sage/libs/pari/meson.build @@ -24,13 +24,32 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cypari2, cysignals, flint, gmp, gsl, mpfr, pari] py.extension_module( name, sources: pyx, subdir: 'sage/libs/pari', install: true, include_directories: [inc_cpython, inc_ext, inc_flint, inc_gsl, inc_rings], - dependencies: [py_dep, cypari2, cysignals, flint, gmp, gsl, mpfr, pari], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs/pari', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/libs/singular/meson.build b/src/sage/libs/singular/meson.build index 52ece586caa..264fd9f5470 100644 --- a/src/sage/libs/singular/meson.build +++ b/src/sage/libs/singular/meson.build @@ -21,6 +21,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, cysignals, givaro, gmp, singular] py.extension_module( name, sources: pyx, @@ -28,7 +29,25 @@ foreach name, pyx : extension_data_cpp install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython, inc_ntl, inc_rings, inc_rings_finite], - dependencies: [py_dep, cysignals, givaro, gmp, singular], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs/singular', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/libs/symmetrica/all.py b/src/sage/libs/symmetrica/all.py index f69490654af..bc36f1d841c 100644 --- a/src/sage/libs/symmetrica/all.py +++ b/src/sage/libs/symmetrica/all.py @@ -1,4 +1,5 @@ # from symmetrica import * +from sage.features import FeatureNotPresentError from sage.libs.symmetrica.symmetrica import start @@ -97,4 +98,8 @@ from sage.libs.symmetrica.symmetrica import scalarproduct_schubert_symmetrica as scalarproduct_schubert from sage.libs.symmetrica.symmetrica import divdiff_schubert_symmetrica as divdiff_schubert -start() +try: + start() +except FeatureNotPresentError: + # Symmetrica is not available, so we do nothing + pass diff --git a/src/sage/libs/symmetrica/meson.build b/src/sage/libs/symmetrica/meson.build index 9294ebe3b03..d7eed7eef6e 100644 --- a/src/sage/libs/symmetrica/meson.build +++ b/src/sage/libs/symmetrica/meson.build @@ -6,13 +6,31 @@ py.install_sources('__init__.py', 'all.py', subdir: 'sage/libs/symmetrica') extension_data = {'symmetrica' : files('symmetrica.pyx')} foreach name, pyx : extension_data + deps = [py_dep, cysignals, gmp, symmetrica] py.extension_module( name, sources: pyx, subdir: 'sage/libs/symmetrica', install: true, include_directories: [], - dependencies: [py_dep, cysignals, gmp, symmetrica], + dependencies: deps, ) + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'libs/symmetrica', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/matrix/meson.build b/src/sage/matrix/meson.build index 0e51c764de7..b80c0f58143 100644 --- a/src/sage/matrix/meson.build +++ b/src/sage/matrix/meson.build @@ -126,6 +126,24 @@ foreach name, pyx : extension_data ], dependencies: dependencies, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'matrix', + install: true, + copy: true, + ) + endif endforeach extension_data_cpp = { @@ -142,6 +160,30 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [ + py_dep, + blas, + cypari2, + cysignals, + fflas, + flint, + gd, + givaro, + gmp, + gmpxx, + iml, + linbox, + m, + m4ri, + m4rie, + mpfi, + mpfr, + ntl, + pari, + png, + singular, + zlib, + ] py.extension_module( name, sources: pyx, @@ -157,30 +199,25 @@ foreach name, pyx : extension_data_cpp inc_rings, inc_rings_finite, ], - dependencies: [ - py_dep, - blas, - cypari2, - cysignals, - fflas, - flint, - gd, - givaro, - gmp, - gmpxx, - iml, - linbox, - m, - m4ri, - m4rie, - mpfi, - mpfr, - ntl, - pari, - png, - singular, - zlib, - ], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'matrix', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/meson.build b/src/sage/meson.build index d0cf55161b9..2f83dc2e27e 100644 --- a/src/sage/meson.build +++ b/src/sage/meson.build @@ -63,6 +63,8 @@ config_file = configure_file( configuration: conf_data, ) +not_available = files('features/not_available.py.in') + # Packages that need no processing and can be installed directly no_processing = [ 'databases', diff --git a/src/sage/misc/meson.build b/src/sage/misc/meson.build index 97d4bf9e6a1..7aa87d54f2a 100644 --- a/src/sage/misc/meson.build +++ b/src/sage/misc/meson.build @@ -138,5 +138,23 @@ foreach name, pyx : extension_data include_directories: [inc_cpython, inc_rings], dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'misc', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/modular/arithgroup/meson.build b/src/sage/modular/arithgroup/meson.build index 52475097b34..d088d1b45f2 100644 --- a/src/sage/modular/arithgroup/meson.build +++ b/src/sage/modular/arithgroup/meson.build @@ -19,14 +19,33 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, flint, gmp] py.extension_module( name, sources: pyx, subdir: 'sage/modular/arithgroup', install: true, include_directories: [inc_cpython, inc_ext, inc_flint, inc_rings], - dependencies: [py_dep, cysignals, flint, gmp], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'modular/arithgroup', + install: true, + copy: true, + ) + endif endforeach # Manually create header file, which otherwise is not found @@ -53,6 +72,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, cysignals, flint, gmp, gmpxx] py.extension_module( name, sources: pyx, @@ -60,7 +80,25 @@ foreach name, pyx : extension_data_cpp install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython, inc_ext, inc_flint, inc_rings, inc_src], - dependencies: [py_dep, cysignals, flint, gmp, gmpxx], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'modular/arithgroup', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/modular/modform/meson.build b/src/sage/modular/modform/meson.build index 541227d9511..de2d7543096 100644 --- a/src/sage/modular/modform/meson.build +++ b/src/sage/modular/modform/meson.build @@ -36,13 +36,32 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, flint, gmp] py.extension_module( name, sources: pyx, subdir: 'sage/modular/modform', install: true, include_directories: [inc_cpython, inc_flint, inc_rings], - dependencies: [py_dep, cysignals, flint, gmp], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'modular/modform', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/modular/modsym/meson.build b/src/sage/modular/modsym/meson.build index 15851710402..b343290ef6a 100644 --- a/src/sage/modular/modsym/meson.build +++ b/src/sage/modular/modsym/meson.build @@ -30,13 +30,32 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, flint, gmp] py.extension_module( name, sources: pyx, subdir: 'sage/modular/modsym', install: true, include_directories: [inc_cpython, inc_ext, inc_flint, inc_rings], - dependencies: [py_dep, cysignals, flint, gmp], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'modular/modsym', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/modules/meson.build b/src/sage/modules/meson.build index a5c78e98633..13b7ed9688d 100644 --- a/src/sage/modules/meson.build +++ b/src/sage/modules/meson.build @@ -62,6 +62,7 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, gmp] py.extension_module( name, sources: pyx, @@ -74,7 +75,7 @@ foreach name, pyx : extension_data inc_rings, inc_rings_finite, ], - dependencies: [py_dep, cysignals, gd, gmp, m4ri, png], + dependencies: deps, ) endforeach @@ -84,6 +85,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, cysignals, gd, gmp, m4ri, png] py.extension_module( name, sources: pyx, @@ -97,8 +99,26 @@ foreach name, pyx : extension_data_cpp inc_rings, inc_rings_finite, ], - dependencies: [py_dep, cysignals, gd, gmp, m4ri, png], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'modules', + install: true, + copy: true, + ) + endif endforeach install_subdir('fg_pid', install_dir: sage_install_dir / 'modules') diff --git a/src/sage/modules/with_basis/meson.build b/src/sage/modules/with_basis/meson.build index 7dc1dda551b..ff977fe782d 100644 --- a/src/sage/modules/with_basis/meson.build +++ b/src/sage/modules/with_basis/meson.build @@ -13,13 +13,32 @@ py.install_sources( extension_data = {'indexed_element' : files('indexed_element.pyx')} foreach name, pyx : extension_data + deps = [py_dep, gmp] py.extension_module( name, sources: pyx, subdir: 'sage/modules/with_basis', install: true, include_directories: [inc_cpython, inc_data_structures], - dependencies: [py_dep, gmp], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'modules/with_basis', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/numerical/backends/meson.build b/src/sage/numerical/backends/meson.build index 57eeaeb10b0..37b214431b4 100644 --- a/src/sage/numerical/backends/meson.build +++ b/src/sage/numerical/backends/meson.build @@ -41,14 +41,33 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, glpk, gmp] py.extension_module( name, sources: pyx, subdir: 'sage/numerical/backends', install: true, include_directories: [inc_cpython, inc_rings], - dependencies: [py_dep, cysignals, glpk, gmp], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'numerical/backends', + install: true, + copy: true, + ) + endif endforeach extension_data_cpp = {'scip_backend': files('scip_backend.pyx')} diff --git a/src/sage/numerical/meson.build b/src/sage/numerical/meson.build index 91257af0880..be252b148a3 100644 --- a/src/sage/numerical/meson.build +++ b/src/sage/numerical/meson.build @@ -23,14 +23,33 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cypari2, gmp, mpfr] py.extension_module( name, sources: pyx, subdir: 'sage/numerical', install: true, include_directories: [inc_cpython, inc_rings], - dependencies: [py_dep, cypari2, gmp, mpfr], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'numerical', + install: true, + copy: true, + ) + endif endforeach subdir('backends') diff --git a/src/sage/plot/meson.build b/src/sage/plot/meson.build index 8cb44114959..39fe4b25b13 100644 --- a/src/sage/plot/meson.build +++ b/src/sage/plot/meson.build @@ -36,14 +36,33 @@ py.install_sources( extension_data = {'complex_plot' : files('complex_plot.pyx')} foreach name, pyx : extension_data + deps = [py_dep, cysignals, gmp, gsl] py.extension_module( name, sources: pyx, subdir: 'sage/plot', install: true, include_directories: [inc_cpython, inc_gsl, inc_numpy, inc_rings], - dependencies: [py_dep, cysignals, gmp, gsl], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'plot', + install: true, + copy: true, + ) + endif endforeach subdir('plot3d') diff --git a/src/sage/plot/plot3d/meson.build b/src/sage/plot/plot3d/meson.build index ae1dd2a6b41..41a93123b2a 100644 --- a/src/sage/plot/plot3d/meson.build +++ b/src/sage/plot/plot3d/meson.build @@ -31,9 +31,9 @@ extension_data = { } foreach name, pyx : extension_data - dependencies = [py_dep, cysignals, gmp] + deps = [py_dep, cysignals, gmp] if name == 'parametric_surface' - dependencies += [interpreters_dep] + deps += [interpreters_dep] endif py.extension_module( name, @@ -41,6 +41,24 @@ foreach name, pyx : extension_data subdir: 'sage/plot/plot3d', install: true, include_directories: [inc_cpython, inc_ext, inc_numpy], - dependencies: dependencies, + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'plot/plot3d', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/probability/meson.build b/src/sage/probability/meson.build index 2981a7496c4..61dd82d20fb 100644 --- a/src/sage/probability/meson.build +++ b/src/sage/probability/meson.build @@ -10,13 +10,32 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cysignals, gmp, gsl] py.extension_module( name, sources: pyx, subdir: 'sage/probability', install: true, include_directories: [], - dependencies: [py_dep, cysignals, gmp, gsl], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'probability', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/rings/convert/meson.build b/src/sage/rings/convert/meson.build index 04b9e285593..a0750d2cc91 100644 --- a/src/sage/rings/convert/meson.build +++ b/src/sage/rings/convert/meson.build @@ -8,13 +8,32 @@ py.install_sources( extension_data = {'mpfi' : files('mpfi.pyx')} foreach name, pyx : extension_data + deps = [py_dep, gmp, gsl, mpfi, mpfr] py.extension_module( name, sources: pyx, subdir: 'sage/rings/convert', install: true, include_directories: [inc_cpython, inc_rings], - dependencies: [py_dep, cypari2, gmp, gsl, mpfi, mpfr, pari], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'rings/convert', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/rings/finite_rings/meson.build b/src/sage/rings/finite_rings/meson.build index 7e6c338636f..eda5754c4a8 100644 --- a/src/sage/rings/finite_rings/meson.build +++ b/src/sage/rings/finite_rings/meson.build @@ -63,6 +63,24 @@ foreach name, pyx : extension_data ], dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'rings/finite_rings', + install: true, + copy: true, + ) + endif endforeach extension_data_cpp = { @@ -72,6 +90,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, cypari2, cysignals, givaro, gmp, m, ntl, pari] py.extension_module( name, sources: pyx, @@ -85,7 +104,25 @@ foreach name, pyx : extension_data_cpp inc_rings, inc_rings_finite, ], - dependencies: [py_dep, cypari2, cysignals, givaro, gmp, m, ntl, pari], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'rings/finite_rings', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/rings/imaginary_unit.py b/src/sage/rings/imaginary_unit.py index ae78b38d6c8..d4790178848 100644 --- a/src/sage/rings/imaginary_unit.py +++ b/src/sage/rings/imaginary_unit.py @@ -1,4 +1,8 @@ +from sage.features import FeatureNotPresentError from sage.rings.number_field.number_field import GaussianField -I = GaussianField().gen() +try: + I = GaussianField().gen() +except FeatureNotPresentError: + I = None # Needs NTL diff --git a/src/sage/rings/meson.build b/src/sage/rings/meson.build index 5f4dafdf7c2..4b2846aa463 100644 --- a/src/sage/rings/meson.build +++ b/src/sage/rings/meson.build @@ -176,6 +176,23 @@ foreach name, pyx : extension_data ], dependencies: deps, ) + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'rings', + install: true, + copy: true, + ) + endif endforeach extension_data_cpp = { @@ -220,6 +237,23 @@ foreach name, pyx : extension_data_cpp ], dependencies: deps, ) + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'rings', + install: true, + copy: true, + ) + endif endforeach install_subdir('asymptotic', install_dir: sage_install_dir / 'rings') diff --git a/src/sage/rings/number_field/meson.build b/src/sage/rings/number_field/meson.build index 5b612679d40..16c0d8fc15d 100644 --- a/src/sage/rings/number_field/meson.build +++ b/src/sage/rings/number_field/meson.build @@ -51,6 +51,24 @@ foreach name, pyx : extension_data include_directories: [inc_cpython, inc_ext, inc_flint, inc_ntl, inc_rings], dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'rings/number_field', + install: true, + copy: true, + ) + endif endforeach extension_data_cpp = { @@ -59,6 +77,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, cypari2, cysignals, flint, gmp, mpfi, mpfr, ntl] py.extension_module( name, sources: pyx, @@ -66,7 +85,25 @@ foreach name, pyx : extension_data_cpp install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython, inc_ext, inc_flint, inc_ntl, inc_rings], - dependencies: [py_dep, cypari2, cysignals, flint, gmp, mpfi, mpfr, ntl], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'rings/number_field', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/rings/number_field/totallyreal_data.pyx b/src/sage/rings/number_field/totallyreal_data.pyx index 694e96235bc..67727a078b4 100644 --- a/src/sage/rings/number_field/totallyreal_data.pyx +++ b/src/sage/rings/number_field/totallyreal_data.pyx @@ -30,9 +30,13 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.real_mpfr import RealField from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer +from sage.features import FeatureNotPresentError # Other global variables -ZZx = PolynomialRing(ZZ, 'x') +try: + ZZx = PolynomialRing(ZZ, 'x') +except FeatureNotPresentError: + ZZx = None from libc.math cimport lrint, floor, ceil, fabs, round diff --git a/src/sage/rings/padics/meson.build b/src/sage/rings/padics/meson.build index f589881042e..9430f5a68fc 100644 --- a/src/sage/rings/padics/meson.build +++ b/src/sage/rings/padics/meson.build @@ -88,6 +88,24 @@ foreach name, pyx : extension_data ], dependencies: [py_dep, cypari2, cysignals, flint, gmp, m, ntl], ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'rings/padics', + install: true, + copy: true, + ) + endif endforeach extension_data_cpp = { @@ -120,5 +138,23 @@ foreach name, pyx : extension_data_cpp ], dependencies: [py_dep, cypari2, cysignals, flint, gmp, m, ntl], ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'rings/padics', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/rings/polynomial/meson.build b/src/sage/rings/polynomial/meson.build index a74efed061a..4c4b7905c09 100644 --- a/src/sage/rings/polynomial/meson.build +++ b/src/sage/rings/polynomial/meson.build @@ -123,6 +123,24 @@ foreach name, pyx : extension_data ], dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'rings/polynomial', + install: true, + copy: true, + ) + endif endforeach extension_data_cpp = { @@ -157,20 +175,26 @@ foreach name, pyx : extension_data_cpp inc_rings, inc_rings_finite, ], - dependencies: [ - py_dep, - cypari2, - cysignals, - flint, - givaro, - gmp, - mpfi, - mpfr, - ntl, - pari, - singular, - ], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'rings/polynomial', + install: true, + copy: true, + ) + endif endforeach install_subdir('padics', install_dir: sage_install_dir / 'rings/polynomial') diff --git a/src/sage/rings/polynomial/pbori/meson.build b/src/sage/rings/polynomial/pbori/meson.build index c7541ae492d..891ca95967d 100644 --- a/src/sage/rings/polynomial/pbori/meson.build +++ b/src/sage/rings/polynomial/pbori/meson.build @@ -29,6 +29,7 @@ py.install_sources( extension_data_cpp = {'pbori': files('pbori.pyx')} foreach name, pyx : extension_data_cpp + deps = [py_dep, brial, brial_groebner, cysignals, gmp, m4ri, png] py.extension_module( name, sources: pyx, @@ -36,7 +37,25 @@ foreach name, pyx : extension_data_cpp install: true, override_options: ['cython_language=cpp'], include_directories: [inc_cpython, inc_ext, inc_rings, inc_src], - dependencies: [py_dep, brial, brial_groebner, cysignals, gmp, m4ri, png], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'rings/polynomial/pbori', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 82d8eae3361..60e770146f8 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -141,6 +141,7 @@ import sys +from sage.features.mock import MockInstance from sage.misc.superseded import deprecation from sage.structure.element import Element from sage.structure.category_object import check_default_category @@ -2192,11 +2193,9 @@ def _element_class(): from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_sparse_field return Polynomial_generic_sparse_field if isinstance(base_ring, rational_field.RationalField): - try: - from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint + from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint + if not isinstance(Polynomial_rational_flint, MockInstance): return Polynomial_rational_flint - except ImportError: - pass elif isinstance(base_ring, NumberField): if base_ring.is_absolute(): from sage.rings.polynomial.polynomial_number_field import Polynomial_absolute_number_field_dense @@ -2205,17 +2204,13 @@ def _element_class(): from sage.rings.polynomial.polynomial_number_field import Polynomial_relative_number_field_dense return Polynomial_relative_number_field_dense elif isinstance(base_ring, sage.rings.abc.RealField): - try: - from .polynomial_real_mpfr_dense import PolynomialRealDense + from sage.rings.polynomial.polynomial_real_mpfr_dense import PolynomialRealDense + if not isinstance(PolynomialRealDense, MockInstance): return PolynomialRealDense - except ImportError: - pass elif isinstance(base_ring, sage.rings.abc.ComplexBallField): - try: - from sage.rings.polynomial.polynomial_complex_arb import Polynomial_complex_arb + from sage.rings.polynomial.polynomial_complex_arb import Polynomial_complex_arb + if not isinstance(Polynomial_complex_arb, MockInstance): return Polynomial_complex_arb - except ImportError: - pass from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_dense_field return Polynomial_generic_dense_field diff --git a/src/sage/rings/polynomial/polynomial_ring_constructor.py b/src/sage/rings/polynomial/polynomial_ring_constructor.py index 78074c8a1d2..89082198702 100644 --- a/src/sage/rings/polynomial/polynomial_ring_constructor.py +++ b/src/sage/rings/polynomial/polynomial_ring_constructor.py @@ -21,6 +21,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.features import FeatureNotPresentError from sage.structure.category_object import normalize_names try: @@ -852,7 +853,7 @@ def _multi_variate(base_ring, names, sparse=None, order='degrevlex', implementat try: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular R = MPolynomialRing_libsingular(base_ring, n, names, order) - except (ImportError, TypeError, NotImplementedError): + except FeatureNotPresentError: if implementation is not None: raise else: diff --git a/src/sage/rings/polynomial/weil/meson.build b/src/sage/rings/polynomial/weil/meson.build index 77432ffef30..aa0e3ce2aaa 100644 --- a/src/sage/rings/polynomial/weil/meson.build +++ b/src/sage/rings/polynomial/weil/meson.build @@ -8,13 +8,32 @@ py.install_sources( extension_data = {'weil_polynomials' : files('weil_polynomials.pyx')} foreach name, pyx : extension_data + deps = [py_dep, cysignals, flint, gmp] py.extension_module( name, sources: pyx, subdir: 'sage/rings/polynomial/weil', install: true, include_directories: [inc_cpython, inc_flint, inc_rings, inc_src], - dependencies: [py_dep, cysignals, flint, gmp], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'rings/polynomial/weil', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index 5efa0c87b65..1468bca3c3a 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -54,6 +54,7 @@ import sage.arith.misc import sage.rings.integer import sage.rings.rational +from sage.features import FeatureNotPresentError from sage.rings.integer cimport Integer from sage.rings.integer_ring import ZZ @@ -2080,10 +2081,9 @@ cdef RealDoubleElement global_dummy_element try: from sage.rings.real_double_element_gsl import RealDoubleElement_gsl -except ImportError: - global_dummy_element = RealDoubleElement(0) -else: global_dummy_element = RealDoubleElement_gsl(0) +except FeatureNotPresentError: + global_dummy_element = RealDoubleElement(0) # A global pool for performance when elements are rapidly created and destroyed. # It operates on the following principles: diff --git a/src/sage/rings/species.py b/src/sage/rings/species.py index 494e7020331..abe832d0f16 100644 --- a/src/sage/rings/species.py +++ b/src/sage/rings/species.py @@ -44,6 +44,7 @@ from sage.combinat.integer_vector import IntegerVectors from sage.combinat.partition import Partitions, _Partitions from sage.combinat.sf.sf import SymmetricFunctions +from sage.features import FeatureNotPresentError from sage.groups.perm_gps.constructor import PermutationGroupElement from sage.groups.perm_gps.permgroup import PermutationGroup, PermutationGroup_generic from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -66,8 +67,10 @@ from sage.structure.unique_representation import (UniqueRepresentation, WithPicklingByInitArgs) -GAP_FAIL = libgap.eval('fail') - +try: + GAP_FAIL = libgap.eval('fail') +except FeatureNotPresentError: + GAP_FAIL = None class AtomicSpeciesElement(WithEqualityById, Element, diff --git a/src/sage/schemes/elliptic_curves/meson.build b/src/sage/schemes/elliptic_curves/meson.build index b2a3dda08c9..314107fdd4d 100644 --- a/src/sage/schemes/elliptic_curves/meson.build +++ b/src/sage/schemes/elliptic_curves/meson.build @@ -61,13 +61,32 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cypari2, cysignals, flint, gmp, mpfr, pari] py.extension_module( name, sources: pyx, subdir: 'sage/schemes/elliptic_curves', install: true, include_directories: [inc_cpython, inc_flint, inc_numpy, inc_rings], - dependencies: [py_dep, cypari2, cysignals, flint, gmp, mpfr, pari], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'schemes/elliptic_curves', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/schemes/hyperelliptic_curves/meson.build b/src/sage/schemes/hyperelliptic_curves/meson.build index 170d08baaca..161682369b5 100644 --- a/src/sage/schemes/hyperelliptic_curves/meson.build +++ b/src/sage/schemes/hyperelliptic_curves/meson.build @@ -29,6 +29,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, cysignals, gmp, ntl] py.extension_module( name, sources: pyx, @@ -43,7 +44,25 @@ foreach name, pyx : extension_data_cpp inc_rings_finite, inc_hypellfrob, ], - dependencies: [py_dep, cysignals, gmp, ntl], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'schemes/hyperelliptic_curves', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/stats/distributions/meson.build b/src/sage/stats/distributions/meson.build index db152755b95..9cca09e04e0 100644 --- a/src/sage/stats/distributions/meson.build +++ b/src/sage/stats/distributions/meson.build @@ -19,6 +19,7 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, cypari2, cysignals, gmp, mpfr] py.extension_module( name, sources: pyx, @@ -26,7 +27,25 @@ foreach name, pyx : extension_data subdir: 'sage/stats/distributions', install: true, include_directories: [inc_cpython, inc_rings, inc_src], - dependencies: [py_dep, cypari2, cysignals, gmp, mpfr], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'stats/distributions', + install: true, + copy: true, + ) + endif endforeach diff --git a/src/sage/structure/meson.build b/src/sage/structure/meson.build index 9d0076ef53d..a9df9bca996 100644 --- a/src/sage/structure/meson.build +++ b/src/sage/structure/meson.build @@ -73,6 +73,24 @@ foreach name, pyx : extension_data include_directories: [inc_cpython, inc_ext, inc_rings], dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'structure', + install: true, + copy: true, + ) + endif endforeach install_subdir('proof', install_dir: sage_install_dir / 'structure') diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 1dd2ae070ca..6aebc84093a 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -127,6 +127,7 @@ from sage.structure.coerce_exceptions import CoercionException from sage.structure.coerce_maps cimport (NamedConvertMap, DefaultConvertMap, DefaultConvertMap_unique, CallableConvertMap) from sage.structure.element cimport parent +from sage.features.mock import MockInstance cdef _record_exception(): @@ -569,7 +570,10 @@ cdef class Parent(sage.structure.category_object.CategoryObject): inheritance from categories. """ if not isinstance(cls, type): - raise TypeError(f"element class {cls!r} should be a type") + if isinstance(cls, MockInstance): + cls.raise_error() + else: + raise TypeError(f"element class {cls!r} should be a type") if inherit is None: inherit = (cls.__dictoffset__ != 0) if inherit: diff --git a/src/sage/symbolic/meson.build b/src/sage/symbolic/meson.build index fc1f2a806e3..b4d90ef43e0 100644 --- a/src/sage/symbolic/meson.build +++ b/src/sage/symbolic/meson.build @@ -109,6 +109,7 @@ extension_data_cpp = { } foreach name, pyx : extension_data_cpp + deps = [py_dep, cysignals, gmp, gsl, flint, singular_factory] py.extension_module( name, sources: pyx, @@ -125,8 +126,26 @@ foreach name, pyx : extension_data_cpp inc_rings, include_directories('../libs/gmp'), ], - dependencies: [py_dep, cysignals, gmp, gsl, singular], + dependencies: deps, ) + + all_deps_found = true + foreach dep : deps + if not dep.found() + all_deps_found = false + break + endif + endforeach + if not all_deps_found + configure_file( + input: not_available, + output: name + '.py', + install_tag: 'python-runtime', + install_dir: sage_install_dir / 'symbolic', + install: true, + copy: true, + ) + endif endforeach install_subdir('integration', install_dir: sage_install_dir / 'symbolic')