Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions .github/workflows/core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,18 +113,24 @@ jobs:
. venv-petsctools/bin/activate
pip install --verbose $PETSC_DIR/src/binding/petsc4py

# Make sure that running 'import petsctools' does not initialise PETSc
# (e.g. by running 'from petsc4py import PETSc'). Otherwise 'petsctools.init'
# does nothing. We check this by passing a PETSc option on the command line
# and making sure that it is processed.
- name: Test lazy PETSc initialisation
- name: Test PETSc initialisation
if: success() || steps.install-petsc4py.conclusion == 'success'
run: |
. venv-petsctools/bin/activate

: # Make sure that running 'import petsctools' does not initialise PETSc
: # (e.g. by running 'from petsc4py import PETSc'). Otherwise 'petsctools.init'
: # does nothing. We check this by passing a PETSc option on the command line
: # and making sure that it is processed.
if [ -z "$( python -c 'import petsctools; petsctools.init()' -log_view | grep 'PETSc Performance Summary' )" ]; then
echo "ERROR: '-log_view' flag not passed to PETSc"
exit 1
fi

: # Test that running 'petsctools.init' after PETSc is initialised raises a warning
if [ -z "$( 2>&1 python -c 'import petsc4py, petsctools; petsc4py.init(); petsctools.init()' | grep 'PETSc has already been initialised' )" ]; then
echo "ERROR: petsctools.init should have raised a warning"
exit 1
else
exit 0
fi

- name: Run tests with petsc4py
Expand Down
16 changes: 7 additions & 9 deletions petsctools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from .config import ( # noqa: F401
MissingPetscException,
get_config,
get_petsc_dir,
get_petsc_arch,
Expand All @@ -8,7 +7,12 @@
get_petscconf_h,
get_external_packages,
)
from .exceptions import PetscToolsException # noqa: F401
from .exceptions import ( # noqa: F401
PetscToolsException,
MissingPetscException,
InvalidEnvironmentException,
InvalidPetscVersionException,
)
from .utils import PETSC4PY_INSTALLED

# Now conditionally import the functions that depend on petsc4py. If petsc4py
Expand All @@ -26,11 +30,7 @@
print_citations_at_exit,
)
from .config import get_blas_library # noqa: F401
from .init import ( # noqa: F401
InvalidEnvironmentException,
InvalidPetscVersionException,
init,
)
from .init import init # noqa: F401
from .options import ( # noqa: F401
flatten_parameters,
get_commandline_options,
Expand All @@ -54,8 +54,6 @@ def __getattr__(name):
"cite",
"print_citations_at_exit",
"get_blas_library",
"InvalidEnvironmentException",
"InvalidPetscVersionException",
"init",
"flatten_parameters",
"get_commandline_options",
Expand Down
6 changes: 1 addition & 5 deletions petsctools/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@
import os
import subprocess

from petsctools.exceptions import PetscToolsException


class MissingPetscException(PetscToolsException):
pass
from petsctools.exceptions import MissingPetscException


def get_config():
Expand Down
12 changes: 12 additions & 0 deletions petsctools/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,17 @@ class PetscToolsAppctxException(PetscToolsException):
"""Exception raised when the Appctx is missing an entry."""


class InvalidEnvironmentException(PetscToolsException):
pass


class InvalidPetscVersionException(PetscToolsException):
pass


class MissingPetscException(PetscToolsException):
pass


class PetscToolsWarning(UserWarning):
"""Generic base class for petsctools warnings."""
65 changes: 45 additions & 20 deletions petsctools/init.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,64 @@
import os
import sys
import types
import warnings
from collections.abc import Sequence
from pathlib import Path

import petsc4py
import petsc4py.lib
from packaging.specifiers import SpecifierSet
from packaging.version import Version

import petsctools.options
from petsctools.exceptions import PetscToolsException


class InvalidEnvironmentException(PetscToolsException):
pass


class InvalidPetscVersionException(PetscToolsException):
pass


def init(argv=None, *, version_spec=""):
"""Initialise PETSc."""
import petsc4py

from petsctools.exceptions import (
InvalidEnvironmentException, InvalidPetscVersionException
)


def init(
argv: Sequence[str] | None = None,
*,
version_spec: SpecifierSet | str = "",
) -> types.ModuleType:
"""Initialise PETSc.

Parameters
----------
argv
Command line options to be passed to PETSc at initialisation. If
unspecified then `sys.argv` is used.
version_spec
String describing PETSc version constraints. For example
'>=3.25.2,<3.26'.

Returns
-------
types.ModuleType
The `petsc4py.PETSc` module. This is convenient for avoiding
boilerplate.

"""
if argv is None:
argv = sys.argv

petsc4py.init(argv)
# We have to do this dance because we need to access petsc4py.PETSc without
# initialising PETSc. This is what happens in
# https://gitlab.com/petsc/petsc/-/blob/main/src/binding/petsc4py/src/petsc4py/PETSc.py
PETSc = petsc4py.lib.ImportPETSc()
if PETSc.Sys.isInitialized():
warnings.warn(
"Calling petsctools.init but PETSc has already been initialised, "
"any command line options will be ignored.",
stacklevel=2,
)
else:
PETSc._initialize(argv)

check_environment_matches_petsc4py_config()
check_petsc_version(version_spec)

# Save the command line options so they may be inspected later
from petsc4py import PETSc

petsctools.options._commandline_options = frozenset(
PETSc.Options().getAll()
)
Expand All @@ -40,8 +67,6 @@ def init(argv=None, *, version_spec=""):


def check_environment_matches_petsc4py_config():
import petsc4py

config = petsc4py.get_config()
petsc_dir = config["PETSC_DIR"]
petsc_arch = config["PETSC_ARCH"]
Expand Down
Loading