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

Features/add cli option #147

Merged
merged 15 commits into from
Aug 18, 2022
37 changes: 32 additions & 5 deletions nomenclature/cli.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import click
import ast
from pathlib import Path
from typing import List

from nomenclature.testing import assert_valid_yaml, assert_valid_structure

cli = click.Group()


class PythonLiteralOption(click.Option):
def type_cast_value(self, ctx, value):
try:
return ast.literal_eval(value)
except Exception:
raise click.BadParameter(value)


@cli.command("validate-yaml")
@click.argument("path", type=click.Path(exists=True, path_type=Path))
def cli_valid_yaml(path: Path):
Expand All @@ -15,9 +25,24 @@ def cli_valid_yaml(path: Path):

@cli.command("validate-project")
@click.argument("path", type=click.Path(exists=True, path_type=Path))
@click.option("--mappings", type=str, default="mappings")
@click.option("--definitions", type=str, default="definitions")
def cli_valid_project(path: Path, mappings: str, definitions: str):
@click.option(
luciecastella marked this conversation as resolved.
Show resolved Hide resolved
"--dimensions",
help="Optional list of dimensions",
cls=PythonLiteralOption,
default="['region', 'variable']",
)
@click.option(
"--mappings", help="Optional name for mappings folder", type=str, default="mappings"
)
@click.option(
"--definitions",
help="Optional name for definitions folder",
type=str,
default="definitions",
)
def cli_valid_project(
path: Path, dimensions: List[str], mappings: str, definitions: str
):
"""Assert that `path` is a valid project nomenclature

This test includes three steps:
Expand All @@ -32,8 +57,10 @@ def cli_valid_project(path: Path, mappings: str, definitions: str):

Example
-------
$ nomenclature validate-project . --definitions <def-folder> --mappings <map-folder>
$ nomenclature validate-project .
--dimensions "['<folder1>', '<folder2>', '<folder3>']"
--mappings <map-folder> --definitions <def-folder>

"""
assert_valid_yaml(path)
assert_valid_structure(path, mappings, definitions)
assert_valid_structure(path, dimensions, mappings, definitions)
10 changes: 8 additions & 2 deletions nomenclature/testing.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import yaml
import logging
from pathlib import Path
from typing import List

import nomenclature

Expand Down Expand Up @@ -28,14 +29,19 @@ def assert_valid_yaml(path: Path):


def assert_valid_structure(
path: Path, mappings: str = "mappings", definitions: str = "definitions"
path: Path,
luciecastella marked this conversation as resolved.
Show resolved Hide resolved
dimensions: List[str] = ["region", "variable"],
mappings: str = "mappings",
definitions: str = "definitions",
) -> None:
"""Assert that `path` can be initialized as a :class:`DataStructureDefinition`

Parameters
----------
path : Path
directory path to the file of interest
dimensions : List[str]
Optionnal list of dimensions to be checked
mappings : str
Optionnal non-default name for the mappings folder
definitions : str
Expand All @@ -50,7 +56,7 @@ def assert_valid_structure(

"""

definition = nomenclature.DataStructureDefinition(path / str(definitions))
definition = nomenclature.DataStructureDefinition(path / definitions, dimensions)
if (path / mappings).is_dir():
nomenclature.RegionProcessor.from_directory(path / mappings).validate_mappings(
definition
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- common:
- World
- country:
- Austria
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Primary Energy:
definition: Total primary energy consumption
unit: EJ/yr
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
model: model_a
native_regions:
- World
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
model: model_b
common_regions:
- World:
- region_a
- region_b
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- common:
- World
- country:
- Austria
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- first_scenario
- second_scenario:
description : this is a nice description

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Primary Energy:
definition: Total primary energy consumption
unit: EJ/yr
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
model: model_a
native_regions:
- World
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
model: model_b
common_regions:
- World:
- region_a
- region_b
46 changes: 46 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,49 @@ def test_cli_wrong_definitions_name():
],
)
assert result_valid.exit_code == 1


def test_cli_custom_dimensions():
"""Check that CLI runs through with a non-default dimension"""

result_valid = runner.invoke(
cli,
[
"validate-project",
str(TEST_DATA_DIR / "non-default_dimensions_passing"),
"--dimensions",
"['variable', 'region', 'scenario']",
],
)
assert result_valid.exit_code == 0


def test_cli_custom_dimensions_empty():
"""Check that CLI raises an error when specifying an empty directory ('empty')"""

result_valid = runner.invoke(
cli,
[
"validate-project",
str(TEST_DATA_DIR / "non-default_dimensions_failing"),
"--dimensions",
"['variable', 'region', 'empty']",
],
)
assert result_valid.exit_code == 1


def test_cli_custom_dimensions_fails():
"""Check that CLI raises an error when specifying a non-existent
directory ('foo')"""

result_valid = runner.invoke(
cli,
[
"validate-project",
str(TEST_DATA_DIR / "non-default_dimensions_passing"),
"--dimensions",
"['variable', 'region', 'foo']",
],
)
assert result_valid.exit_code == 1