Skip to content

Commit

Permalink
New load_likelihood_from_module. (#341)
Browse files Browse the repository at this point in the history
Co-authored-by: Marc Paterno <paterno@fnal.gov>
  • Loading branch information
vitenti and marcpaterno authored Oct 30, 2023
1 parent 6d12faf commit 829ce76
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 55 deletions.
142 changes: 103 additions & 39 deletions firecrown/likelihood/likelihood.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from __future__ import annotations
from typing import Mapping, Tuple, Union, Optional
from abc import abstractmethod
import types
import warnings
import importlib
import importlib.util
Expand Down Expand Up @@ -146,7 +147,66 @@ def to_set(self):
return set(self.data)


def load_likelihood(
def load_likelihood_from_module_type(
module: types.ModuleType, build_parameters: NamedParameters
) -> Tuple[Likelihood, ModelingTools]:
"""Loads a likelihood and returns a tuple of the likelihood and
the modeling tools.
This function is used by both :python:`load_likelihood_from_script` and
:python:`load_likelihood_from_module`. It is not intended to be called
directly.
:param module: a loaded module
:param build_parameters: a NamedParameters object containing the factory
function parameters
"""

if not hasattr(module, "build_likelihood"):
if not hasattr(module, "likelihood"):
raise AttributeError(
f"Firecrown initialization module {module.__name__} in "
f"{module.__file__} does not define "
f"a `build_likelihood` factory function."
)
warnings.simplefilter("always", DeprecationWarning)
warnings.warn(
"The use of a likelihood variable in Firecrown's initialization "
"module is deprecated. Any parameters passed to the likelihood "
"will be ignored. The module should define a `build_likelihood` "
"factory function.",
category=DeprecationWarning,
)
likelihood = module.likelihood
tools = ModelingTools()
else:
if not callable(module.build_likelihood):
raise TypeError(
"The factory function `build_likelihood` must be a callable."
)
build_return = module.build_likelihood(build_parameters)
if isinstance(build_return, tuple):
likelihood, tools = build_return
else:
likelihood = build_return
tools = ModelingTools()

if not isinstance(likelihood, Likelihood):
raise TypeError(
f"The returned likelihood must be a Firecrown's `Likelihood` type, "
f"received {type(likelihood)} instead."
)

if not isinstance(tools, ModelingTools):
raise TypeError(
f"The returned tools must be a Firecrown's `ModelingTools` type, "
f"received {type(tools)} instead."
)

return likelihood, tools


def load_likelihood_from_script(
filename: str, build_parameters: NamedParameters
) -> Tuple[Likelihood, ModelingTools]:
"""Loads a likelihood script and returns a tuple of the likelihood and
Expand Down Expand Up @@ -189,44 +249,48 @@ def load_likelihood(
assert spec.loader is not None
spec.loader.exec_module(mod)

if not hasattr(mod, "build_likelihood"):
if not hasattr(mod, "likelihood"):
raise AttributeError(
f"Firecrown initialization script {filename} does not define "
f"a `build_likelihood` factory function."
)
warnings.simplefilter("always", DeprecationWarning)
warnings.warn(
"The use of a likelihood variable in Firecrown's initialization "
"script is deprecated. Any parameters passed to the likelihood "
"will be ignored. The script should define a `build_likelihood` "
"factory function.",
category=DeprecationWarning,
)
likelihood = mod.likelihood
tools = ModelingTools()
else:
if not callable(mod.build_likelihood):
raise TypeError(
"The factory function `build_likelihood` must be a callable."
)
build_return = mod.build_likelihood(build_parameters)
if isinstance(build_return, tuple):
likelihood, tools = build_return
else:
likelihood = build_return
tools = ModelingTools()
return load_likelihood_from_module_type(mod, build_parameters)

if not isinstance(likelihood, Likelihood):
raise TypeError(
f"The returned likelihood must be a Firecrown's `Likelihood` type, "
f"received {type(likelihood)} instead."
)

if not isinstance(tools, ModelingTools):
raise TypeError(
f"The returned tools must be a Firecrown's `ModelingTools` type, "
f"received {type(tools)} instead."
)
def load_likelihood_from_module(
module: str, build_parameters: NamedParameters
) -> Tuple[Likelihood, ModelingTools]:
"""Loads a likelihood and returns a tuple of the likelihood and
the modeling tools.
return likelihood, tools
:param module: module name
:param build_parameters: a NamedParameters object containing the factory
function parameters
"""

try:
mod = importlib.import_module(module)
except ImportError as exc:
raise ValueError(
f"Unrecognized Firecrown initialization module {module}."
) from exc

return load_likelihood_from_module_type(mod, build_parameters)


def load_likelihood(
likelihood_name: str, build_parameters: NamedParameters
) -> Tuple[Likelihood, ModelingTools]:
"""Loads a likelihood and returns a tuple of the likelihood and
the modeling tools.
:param likelihood_name: script filename or module name
:param build_parameters: a NamedParameters object containing the factory
function parameters
"""

try:
return load_likelihood_from_script(likelihood_name, build_parameters)
except ValueError:
try:
return load_likelihood_from_module(likelihood_name, build_parameters)
except ValueError as exc:
raise ValueError(
f"Unrecognized Firecrown initialization file or module "
f"{likelihood_name}."
) from exc
78 changes: 62 additions & 16 deletions tests/likelihood/test_likelihood.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,90 +2,136 @@
Tests for the module firecrown.likelihood.likelihood.
"""
import os
import sys
import pytest

from firecrown.likelihood.likelihood import load_likelihood, NamedParameters
from firecrown.likelihood.likelihood import (
load_likelihood_from_script,
load_likelihood_from_module,
load_likelihood,
NamedParameters,
)


def test_load_likelihood_submodule():
def test_load_likelihood_from_script_submodule():
dir_path = os.path.dirname(os.path.realpath(__file__))

load_likelihood(os.path.join(dir_path, "lkdir/lkscript.py"), NamedParameters())
load_likelihood_from_script(
os.path.join(dir_path, "lkdir/lkscript.py"), NamedParameters()
)


def test_load_likelihood_submodule_invalid():
def test_load_likelihood_from_script_submodule_invalid():
dir_path = os.path.dirname(os.path.realpath(__file__))

with pytest.raises(ValueError, match="Unrecognized Firecrown initialization file"):
load_likelihood(
load_likelihood_from_script(
os.path.join(dir_path, "lkdir/lkscript_invalid.ext"), NamedParameters()
)


def test_load_likelihood_submodule_no_build_likelihood():
def test_load_likelihood_from_script_submodule_no_build_likelihood():
dir_path = os.path.dirname(os.path.realpath(__file__))

with pytest.raises(
AttributeError, match="does not define a `build_likelihood` factory function."
):
load_likelihood(
load_likelihood_from_script(
os.path.join(dir_path, "lkdir/lkscript_invalid.py"), NamedParameters()
)


def test_load_likelihood_submodule_not_a_function():
def test_load_likelihood_from_script_submodule_not_a_function():
dir_path = os.path.dirname(os.path.realpath(__file__))

with pytest.raises(
TypeError, match="The factory function `build_likelihood` must be a callable."
):
load_likelihood(
load_likelihood_from_script(
os.path.join(dir_path, "lkdir/lkscript_not_a_function.py"),
NamedParameters(),
)


def test_load_likelihood_submodule_returns_wrong_type():
def test_load_likelihood_from_script_submodule_returns_wrong_type():
dir_path = os.path.dirname(os.path.realpath(__file__))

with pytest.raises(
TypeError,
match="The returned likelihood must be a Firecrown's `Likelihood` type,",
):
load_likelihood(
load_likelihood_from_script(
os.path.join(dir_path, "lkdir/lkscript_returns_wrong_type.py"),
NamedParameters(),
)


def test_load_likelihood_submodule_returns_wrong_type_tools():
def test_load_likelihood_from_script_submodule_returns_wrong_type_tools():
dir_path = os.path.dirname(os.path.realpath(__file__))

with pytest.raises(
TypeError,
match="The returned tools must be a Firecrown's `ModelingTools` type",
):
load_likelihood(
load_likelihood_from_script(
os.path.join(dir_path, "lkdir/lkscript_returns_wrong_type_tools.py"),
NamedParameters(),
)


def test_load_likelihood_submodule_old():
def test_load_likelihood_from_script_submodule_old():
dir_path = os.path.dirname(os.path.realpath(__file__))

with pytest.deprecated_call():
load_likelihood(
load_likelihood_from_script(
os.path.join(dir_path, "lkdir/lkscript_old.py"),
NamedParameters(),
)


def test_load_likelihood_correct_tools():
def test_load_likelihood_from_script_correct_tools():
dir_path = os.path.dirname(os.path.realpath(__file__))

_, tools = load_likelihood_from_script(
os.path.join(dir_path, "lkdir/lkscript.py"), NamedParameters()
)

assert tools.test_attribute == "test" # type: ignore


def test_load_likelihood():
dir_path = os.path.dirname(os.path.realpath(__file__))

_, tools = load_likelihood(
os.path.join(dir_path, "lkdir/lkscript.py"), NamedParameters()
)

assert tools.test_attribute == "test" # type: ignore


def test_load_likelihood_from_module():
dir_path = os.path.dirname(os.path.realpath(__file__))
module_path = os.path.join(dir_path, "lkdir")

sys.path.append(module_path)

_, tools = load_likelihood("lkscript", NamedParameters())

assert tools.test_attribute == "test" # type: ignore


def test_load_likelihood_from_module_not_in_path():
with pytest.raises(
ValueError,
match="Unrecognized Firecrown initialization module lkscript_not_in_path.",
):
_ = load_likelihood_from_module("lkscript_not_in_path", NamedParameters())


def test_load_likelihood_not_in_path():
with pytest.raises(
ValueError,
match="Unrecognized Firecrown initialization file or module "
"lkscript_not_in_path.",
):
_ = load_likelihood("lkscript_not_in_path", NamedParameters())

0 comments on commit 829ce76

Please sign in to comment.