Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapt pysteps to allow for nowcast plugins. #418

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
08de598
adding the dgmr model to be directly imported by pysteps.nowcasts
Loickemajou Aug 8, 2024
f26bef5
added the discover nowcasts and the nowcasts_info methods
Loickemajou Aug 8, 2024
ab1b082
added the discover nowcasts at the end so that the new nowcasts metho…
Loickemajou Aug 8, 2024
08ea3cd
added the discover nowcasts and the nowcasts_info methods, to discove…
Loickemajou Aug 8, 2024
bcb7ba9
corrected the discover_nowcast method import
Loickemajou Aug 8, 2024
6f36867
reformatted interface.py
Loickemajou Aug 8, 2024
24d6c41
reformatted __init__.py
Loickemajou Aug 8, 2024
3f5d31a
reformatted interface.py
Loickemajou Aug 8, 2024
b37ce1d
added the test for the modified nowccast interfaces
Loickemajou Aug 12, 2024
cd36341
adding the test for the modified nowcasts methods
Loickemajou Aug 12, 2024
0cd6aa2
reformatted interface.py
Loickemajou Aug 12, 2024
b9dc46d
testing the modified nowcasts interface
Loickemajou Aug 12, 2024
a8a401f
fix some bugs in the discover nowcasts
Loickemajou Aug 19, 2024
d50b78c
added some test to pass the code coverage
Loickemajou Aug 19, 2024
998d076
fi
Loickemajou Aug 19, 2024
aa81fe8
fix some bugs in the discover nowcasts
Loickemajou Aug 19, 2024
54e2dd8
remove the dgmr module package
Loickemajou Aug 26, 2024
4b12402
removed the dgmr in the implimented methods
Loickemajou Aug 26, 2024
c063be5
adding a test for the nowcast pluging discovery
Loickemajou Aug 26, 2024
c790b02
reformatted __init__.py
Loickemajou Aug 26, 2024
ac9f65e
Remove nowcast plugin testing code. The code can be tested from the d…
ladc Aug 27, 2024
45070d4
Remove debug message in discover_nowcasts(); fix comment.
ladc Sep 9, 2024
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
1 change: 1 addition & 0 deletions pysteps/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,4 @@ def load_config_file(params_file=None, verbose=False, dryrun=False):

# After the sub-modules are loaded, register the discovered importers plugin.
io.interface.discover_importers()
nowcasts.interface.discover_nowcasts()
2 changes: 1 addition & 1 deletion pysteps/nowcasts/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Implementations of deterministic and ensemble nowcasting methods."""

from pysteps.nowcasts.interface import get_method
from pysteps.nowcasts.interface import discover_nowcasts, nowcasts_info, get_method
92 changes: 92 additions & 0 deletions pysteps/nowcasts/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
get_method
"""

from pprint import pprint
from pysteps import nowcasts
import importlib
from pysteps.extrapolation.interface import eulerian_persistence
from pysteps.nowcasts import (
anvil,
Expand All @@ -39,7 +42,10 @@
steps,
sseps,
)

from pysteps.nowcasts import lagrangian_probability
import os


_nowcast_methods = dict()
_nowcast_methods["anvil"] = anvil.forecast
Expand All @@ -54,6 +60,91 @@
_nowcast_methods["steps"] = steps.forecast


def discover_nowcasts():
"""
Search for installed nowcasts plugins in the entrypoint 'pysteps.plugin.nowcasts'

The nowcasts method found are added to the `pysteps.nowcasts.interface_nowcasts_methods`
dictionary containing the available nowcasts_methods.
"""

# The pkg resources needs to be reload to detect new packages installed during
# the execution of the python application. For example, when the plugins are
# installed during the tests
import pkg_resources

importlib.reload(pkg_resources)

for entry_point in pkg_resources.iter_entry_points(
group="pysteps.plugins.nowcasts", name=None
):
_module = entry_point.load()
nowcast_module_name = entry_point.name

Check warning on line 82 in pysteps/nowcasts/interface.py

View check run for this annotation

Codecov / codecov/patch

pysteps/nowcasts/interface.py#L81-L82

Added lines #L81 - L82 were not covered by tests

if nowcast_module_name not in _nowcast_methods:
_nowcast_methods[nowcast_module_name] = _module

Check warning on line 85 in pysteps/nowcasts/interface.py

View check run for this annotation

Codecov / codecov/patch

pysteps/nowcasts/interface.py#L84-L85

Added lines #L84 - L85 were not covered by tests

else:
RuntimeWarning(

Check warning on line 88 in pysteps/nowcasts/interface.py

View check run for this annotation

Codecov / codecov/patch

pysteps/nowcasts/interface.py#L88

Added line #L88 was not covered by tests
f"The Nowcasts methode '{nowcast_module_name}' is already available in"
"'pysteps.nowcasts._nowcasts_methods'.\n"
f"Skipping {entry_point.module_name}:{'.'.join(entry_point.attrs)}"
)
if hasattr(nowcasts, nowcast_module_name):
RuntimeWarning(

Check warning on line 94 in pysteps/nowcasts/interface.py

View check run for this annotation

Codecov / codecov/patch

pysteps/nowcasts/interface.py#L93-L94

Added lines #L93 - L94 were not covered by tests
f"The nowcasts method '{nowcast_module_name}' is already an attribute"
"of 'pysteps.nowcasts'.\n"
f"Skipping {entry_point.module_name}:{'.'.join(entry_point.attrs)}"
)
else:
setattr(nowcasts, nowcast_module_name, _module)

Check warning on line 100 in pysteps/nowcasts/interface.py

View check run for this annotation

Codecov / codecov/patch

pysteps/nowcasts/interface.py#L100

Added line #L100 was not covered by tests


def nowcasts_info():
"""Print all the available nowcast methods."""

# nowcasts methods available in the `nowcasts` package
available_nowcasts = [
attr.split(".")[0]
for attr in os.listdir(" ".join(nowcasts.__path__))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Loickemajou Is there a more elegant way to detect all the nowcast methods that doesn't use os.listdir?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ladc, for the remark.

I will take time to look into alternative approaches and see if I can find a more elegant way to achieve this.

if not attr.startswith("__") and attr != "interface.py"
]
print("\nMethods available in the pysteps.nowcasts")
pprint(available_nowcasts)
# nowcasts declared in the pysteps.nowcast interface

nowcasts_in_the_interface = [f for f in _nowcast_methods.keys()]

print("\nMethods available in the pysteps.nowcasts.get_method interface")
pprint([(short_name, f.__name__) for short_name, f in _nowcast_methods.items()])

# Let's use sets to find out if there are importers present in the importer module
# but not declared in the interface, and viceversa.
available_nowcasts = set(available_nowcasts)
nowcasts_in_the_interface = set(nowcasts_in_the_interface)

difference = available_nowcasts ^ nowcasts_in_the_interface
if len(difference) > 0:
print("\nIMPORTANT:")
_diff = available_nowcasts - nowcasts_in_the_interface
if len(_diff) > 0:
print(
"\nIMPORTANT:\nThe following importers are available in pysteps.nowcasts module "
"but not in the pysteps.nowcasts.get_method interface"
)
pprint(_diff)
_diff = nowcasts_in_the_interface - available_nowcasts
if len(_diff) > 0:
print(
"\nWARNING:\n"
"The following importers are available in the pysteps.nowcasts.get_method "
"interface but not in the pysteps.nowcasts module"
)
pprint(_diff)

return available_nowcasts, nowcasts_in_the_interface


def get_method(name):
"""
Return a callable function for computing nowcasts.
Expand Down Expand Up @@ -90,6 +181,7 @@
| sseps | short-space ensemble prediction system (SSEPS). |
| | Essentially, this is a localization of STEPS |
+-----------------+-------------------------------------------------------+

"""
if isinstance(name, str):
name = name.lower()
Expand Down
14 changes: 14 additions & 0 deletions pysteps/tests/test_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,20 @@ def test_nowcasts_interface():
for i in range(num_timesteps):
assert numpy.all(forecast[i] == precip)

# Test for invalid method types
with pytest.raises(ValueError):
pysteps.nowcasts.interface.get_method("linear")

assert isinstance(
pysteps.nowcasts.interface.nowcasts_info()[0],
set,
)

assert isinstance(
pysteps.nowcasts.interface.nowcasts_info()[1],
set,
)


def test_utils_interface():
"""Test utils module interface."""
Expand Down
1 change: 0 additions & 1 deletion pysteps/tests/test_plugins_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import sys
import tempfile


__ = pytest.importorskip("cookiecutter")
from cookiecutter.main import cookiecutter

Expand Down