1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
--- a/python/dolfinx/__init__.py
+++ b/python/dolfinx/__init__.py
@@ -27,6 +27,29 @@
default_scalar_type = _np.float64
default_real_type = _np.float64
+import pusimp
+
+def pip_uninstall_call(executable: str, dependency_pypi_name: str, dependency_actual_path: str) -> str:
+ """Report to the user how to uninstall a dependency with pip."""
+ output = f"{executable} -m pip uninstall --break-system-packages {dependency_pypi_name}"
+ if dependency_actual_path.startswith("/usr"):
+ return f"sudo {output}"
+ else:
+ return output
+
+
+pusimp.prevent_user_site_imports(
+ "dolfinx", "apt", "https://fenicsproject.discourse.group/",
+ "/usr/lib/python3/dist-packages",
+ ["basix", "ffcx", "ufl"],
+ ["fenics-basix", "fenics-ffcx", "fenics-ufl"],
+ [False, False, False],
+ ["", "", ""],
+ pip_uninstall_call
+)
+
+del pip_uninstall_call, pusimp
+
from dolfinx import common
from dolfinx import cpp as _cpp
from dolfinx import fem, geometry, graph, io, jit, la, log, mesh, nls, plot, utils
--- /dev/null
+++ b/python/test/debian-only/test_pusimp.py
@@ -0,0 +1,91 @@
+# Copyright (C) 2024 by the pusimp authors
+#
+# This file is part of pusimp for FEniCSx.
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+"""Test DOLFINx patches."""
+
+import os
+import typing
+
+import pytest
+import requests
+
+from pusimp.utils import (
+ assert_package_import_errors_with_local_packages,
+ assert_package_import_errors_with_broken_non_optional_packages,
+ assert_package_import_success_with_allowed_local_packages,
+ assert_package_import_success_without_local_packages
+)
+
+try:
+ response = requests.get("https://www.debian.org", timeout=5)
+except requests.ConnectionError:
+ has_internet = False
+else:
+ has_internet = True
+
+if os.getenv("PUSIMP_EXPECT_DOLFINX_IN_CWD") is None:
+ dolfinx_python_prefix = "/usr/lib/petsc/lib/python3/dist-packages/dolfinx"
+else:
+ dolfinx_python_prefix = os.path.join(os.getcwd(), "dolfinx")
+
+
+def pip_install_call(executable: str, dependency_pypi_name: str) -> str:
+ """Command to be run to install a dependency with pip."""
+ return (
+ f"{executable} -m pip install --ignore-installed --break-system-packages {dependency_pypi_name}"
+ # debian does not ship numpy 2.0 yet, and a pip install-ed numpy 2.0 would break binary compatibility
+ + " 'numpy<2.0'"
+ )
+
+
+def pip_uninstall_call(executable: str, dependency_pypi_name: str, dependency_actual_path: str) -> str:
+ """Command to be run to uninstall a dependency with pip."""
+ return f"{executable} -m pip uninstall --break-system-packages {dependency_pypi_name}"
+
+
+def test_dolfinx_import_success_without_local_packages() -> None:
+ """Test that dolfinx imports correctly without any extra local packages."""
+ assert_package_import_success_without_local_packages(
+ "dolfinx", os.path.join(dolfinx_python_prefix, "__init__.py")
+ )
+
+
+@pytest.mark.skipif(not has_internet, reason="Requires downloading from pypi.org")
+@pytest.mark.parametrize("dependencies_import_name,dependencies_pypi_name,dependencies_extra_error_message", [
+ (["ufl"], ["fenics-ufl"], []),
+ (["basix", "ufl"], ["fenics-basix", "fenics-ufl"], [])
+])
+def test_dolfinx_import_errors_with_local_packages(
+ dependencies_import_name: typing.List[str], dependencies_pypi_name: typing.List[str],
+ dependencies_extra_error_message: typing.List[str]
+) -> None:
+ """Test that dolfinx fails to import with extra local packages."""
+ assert_package_import_errors_with_local_packages(
+ "dolfinx", dependencies_import_name, dependencies_pypi_name, dependencies_extra_error_message,
+ pip_install_call, pip_uninstall_call
+ )
+
+
+@pytest.mark.skipif(not has_internet, reason="Requires downloading from pypi.org")
+@pytest.mark.parametrize("dependencies_import_name,dependencies_pypi_name", [
+ (["ufl"], ["fenics-ufl"])
+])
+def test_dolfinx_import_success_with_allowed_local_packages(
+ dependencies_import_name: typing.List[str], dependencies_pypi_name: typing.List[str]
+) -> None:
+ """Test that dolfinx imports correctly even with extra local packages when asked to allow user-site imports."""
+ assert_package_import_success_with_allowed_local_packages(
+ "dolfinx", os.path.join(dolfinx_python_prefix, "__init__.py"),
+ dependencies_import_name, dependencies_pypi_name, pip_install_call
+ )
+
+
+@pytest.mark.parametrize("dependencies_import_name", [
+ ["ufl"],
+ ["ffcx"]
+])
+def test_dolfinx_import_errors_with_broken_non_optional_packages(dependencies_import_name: typing.List[str]) -> None:
+ """Test that dolfinx fails to import with broken local packages."""
+ assert_package_import_errors_with_broken_non_optional_packages("dolfinx", dependencies_import_name, [False])
|