Skip to content

Commit

Permalink
feat(CLI): Create command to show available Schedulers (#708)
Browse files Browse the repository at this point in the history
This PR builds upon the previous work done in PR #686, which introduced the command flexmeasures show reporters. Now, we extend this functionality to include the Scheduler class as well. The new command, flexmeasures show schedulers, allows users to view a comprehensive list of all available schedulers within flexmeasures.


* added a new show schedulers cli command

Signed-off-by: Ahmad-Wahid <59763365+Ahmad-Wahid@users.noreply.github.com>

* add changes description in changelog

Signed-off-by: Ahmad-Wahid <59763365+Ahmad-Wahid@users.noreply.github.com>

* created a generic function which creates a list of an item attributes

Signed-off-by: Ahmad-Wahid <59763365+Ahmad-Wahid@users.noreply.github.com>

* Load schedulers from plugins, too

Signed-off-by: F.N. Claessen <felix@seita.nl>

* Find classes in __init__.py files, too

Signed-off-by: F.N. Claessen <felix@seita.nl>

* fix: extract classes from the base module as well

Signed-off-by: Victor Garcia Reolid <victor@seita.nl>

---------

Signed-off-by: Ahmad-Wahid <59763365+Ahmad-Wahid@users.noreply.github.com>
Signed-off-by: F.N. Claessen <felix@seita.nl>
Signed-off-by: Victor Garcia Reolid <victor@seita.nl>
Co-authored-by: F.N. Claessen <felix@seita.nl>
Co-authored-by: Victor Garcia Reolid <victor@seita.nl>
  • Loading branch information
3 people committed Jun 9, 2023
1 parent e4c77cc commit 726cd32
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 28 deletions.
1 change: 1 addition & 0 deletions documentation/changelog.rst
Expand Up @@ -13,6 +13,7 @@ New features
* Introduction of the classes `Reporter` and `PandasReporter` [see `PR #641 <https://www.github.com/FlexMeasures/flexmeasures/pull/641>`_]
* Add CLI command ``flexmeasures add report`` [see `PR #659 <https://www.github.com/FlexMeasures/flexmeasures/pull/659>`_]
* Add CLI command ``flexmeasures show reporters`` [see `PR #686 <https://www.github.com/FlexMeasures/flexmeasures/pull/686>`_]
* Add CLI command ``flexmeasures show schedulers`` [see `PR #708 <https://github.com/FlexMeasures/flexmeasures/pull/708>`_]

Bugfixes
-----------
Expand Down
1 change: 1 addition & 0 deletions documentation/cli/commands.rst
Expand Up @@ -55,6 +55,7 @@ of which some are referred to in this documentation.
``flexmeasures show data-sources`` List available data sources.
``flexmeasures show beliefs`` Plot time series data.
``flexmeasures show reporters`` List available reporters.
``flexmeasures show schedulers`` List available schedulers.
================================================= =======================================


Expand Down
7 changes: 4 additions & 3 deletions flexmeasures/app.py
Expand Up @@ -99,11 +99,12 @@ def create( # noqa C901

register_db_at(app)

# Register Reporters
# Register Reporters and Schedulers
from flexmeasures.utils.coding_utils import get_classes_module
from flexmeasures.data.models.reporting import Reporter
from flexmeasures.data.models import reporting, planning

app.reporters = get_classes_module("flexmeasures.data.models.reporting", Reporter)
app.reporters = get_classes_module("flexmeasures.data.models", reporting.Reporter)
app.schedulers = get_classes_module("flexmeasures.data.models", planning.Scheduler)

# add auth policy

Expand Down
40 changes: 30 additions & 10 deletions flexmeasures/cli/data_show.py
Expand Up @@ -376,28 +376,48 @@ def plot_beliefs(
click.secho("Data saved to file.", **MsgStyle.SUCCESS)


@fm_show_data.command("reporters")
@with_appcontext
def list_reporters():
def list_items(item_type):
"""
Show available reporters.
Show available items of a specific type.
"""

click.echo("Reporters:\n")
click.echo(f"{item_type.capitalize()}:\n")
click.echo(
tabulate(
[
(
reporter_name,
reporter_class.__version__,
reporter_class.__author__,
reporter_class.__module__,
item_name,
item_class.__version__,
item_class.__author__,
item_class.__module__,
)
for reporter_name, reporter_class in app.reporters.items()
for item_name, item_class in getattr(app, item_type).items()
],
headers=["name", "version", "author", "module"],
)
)


@fm_show_data.command("reporters")
@with_appcontext
def list_reporters():
"""
Show available reporters.
"""

with app.app_context():
list_items("reporters")


@fm_show_data.command("schedulers")
@with_appcontext
def list_schedulers():
"""
Show available schedulers.
"""

with app.app_context():
list_items("schedulers")


app.cli.add_command(fm_show_data)
41 changes: 27 additions & 14 deletions flexmeasures/utils/coding_utils.py
Expand Up @@ -173,34 +173,47 @@ def wrapper(*args, **kwargs):
return decorator


def find_classes_module(module, superclass, skiptest=True):
def find_classes_module(module, superclass):
classes = []
reporting_module = importlib.import_module(module)

for submodule in pkgutil.iter_modules(reporting_module.__path__):
module_object = importlib.import_module(f"{module}")
module_classes = inspect.getmembers(module_object, inspect.isclass)

classes.extend(
[
(class_name, klass)
for class_name, klass in module_classes
if issubclass(klass, superclass) and klass != superclass
]
)

return classes


def find_classes_modules(module, superclass, skiptest=True):
classes = []

base_module = importlib.import_module(module)

# root (__init__.py) of the base module
classes += find_classes_module(module, superclass)

for submodule in pkgutil.iter_modules(base_module.__path__):

if skiptest and ("test" in f"{module}.{submodule.name}"):
continue

if submodule.ispkg:
classes.extend(
find_classes_module(
find_classes_modules(
f"{module}.{submodule.name}", superclass, skiptest=skiptest
)
)
else:
module_object = importlib.import_module(f"{module}.{submodule.name}")
module_classes = inspect.getmembers(module_object, inspect.isclass)
classes.extend(
[
(class_name, klass)
for class_name, klass in module_classes
if issubclass(klass, superclass) and klass != superclass
]
)
classes += find_classes_module(f"{module}.{submodule.name}", superclass)

return classes


def get_classes_module(module, superclass, skiptest=True) -> dict:
return dict(find_classes_module(module, superclass, skiptest=skiptest))
return dict(find_classes_modules(module, superclass, skiptest=skiptest))
4 changes: 3 additions & 1 deletion flexmeasures/utils/plugin_utils.py
Expand Up @@ -102,10 +102,12 @@ def register_plugins(app: Flask):
app.logger.debug(f"Registering {plugin_blueprint} ...")
app.register_blueprint(plugin_blueprint)

# Loading reporters
# Load reporters and schedulers
from flexmeasures.data.models.reporting import Reporter
from flexmeasures.data.models.planning import Scheduler

app.reporters.update(get_classes_module(module.__name__, Reporter))
app.schedulers.update(get_classes_module(module.__name__, Scheduler))

app.config["LOADED_PLUGINS"][plugin_name] = plugin_version
app.logger.info(f"Loaded plugins: {app.config['LOADED_PLUGINS']}")
Expand Down

0 comments on commit 726cd32

Please sign in to comment.