-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor the nomenclature into an installable package (#38)
- Loading branch information
1 parent
d19a996
commit 539c26d
Showing
38 changed files
with
209 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
from pathlib import Path | ||
import logging | ||
import yaml | ||
from pyam import IamDataFrame | ||
|
||
# set up logging formatting | ||
logger = logging.getLogger(__name__) | ||
stderr_info_handler = logging.StreamHandler() | ||
formatter = logging.Formatter('%(name)s - %(levelname)s: %(message)s') | ||
stderr_info_handler.setFormatter(formatter) | ||
logger.addHandler(stderr_info_handler) | ||
|
||
|
||
# path to nomenclature definitions | ||
DEF_PATH = Path(__file__).parent / 'definitions' | ||
|
||
|
||
def _parse_yaml(path, file='**/*', ext='.yaml'): | ||
"""Parse `file` in `path` (or all files in subfolders if `file='**/*'`)""" | ||
dct = {} | ||
for f in path.glob(f'{file}{ext}'): | ||
with open(f, 'r') as stream: | ||
_dct = yaml.safe_load(stream) | ||
# add `file` attribute to each element in the dictionary | ||
for key, value in _dct.items(): | ||
value['file'] = str(f) | ||
dct.update(_dct) | ||
return dct | ||
|
||
|
||
variables = _parse_yaml(DEF_PATH / 'variable') | ||
"""Dictionary of variables""" | ||
|
||
|
||
regions = _parse_yaml(DEF_PATH / 'region') | ||
"""Dictionary of all regions""" | ||
|
||
|
||
countries = _parse_yaml(DEF_PATH / 'region', 'countries') | ||
"""Dictionary of countries""" | ||
|
||
|
||
iso_mapping = dict( | ||
[(countries[c]['iso3'], c) for c in countries] | ||
+ [(countries[c]['iso2'], c) for c in countries] | ||
# add alternative iso2 codes used by the European Commission to the mapping | ||
+ [(countries[c]['iso2_alt'], c) for c in countries | ||
if 'iso2_alt' in countries[c]] | ||
) | ||
"""Dictionary of iso2/iso3/alternative-iso2 codes to country names""" | ||
|
||
|
||
def _add_to(mapping, key, value): | ||
"""Add key-value to mapping""" | ||
if key not in mapping: | ||
mapping[key] = value | ||
elif isinstance(value, list): | ||
mapping[key] += value | ||
return mapping[key] | ||
|
||
|
||
def _create_nuts3_hierarchy(): | ||
"""Parse nuts3.yaml and create hierarchical dictionary""" | ||
hierarchy = dict() | ||
keys = ['country', 'nuts1', 'nuts2'] | ||
for n3, mapping in _parse_yaml(DEF_PATH / 'region', 'nuts3').items(): | ||
country, n1, n2 = [mapping.get(i) for i in keys] | ||
country_dict = _add_to(hierarchy, country, {n1: dict()}) | ||
n1_dict = _add_to(country_dict, n1, {n2: list()}) | ||
_add_to(n1_dict, n2, [n3]) | ||
return hierarchy | ||
|
||
|
||
nuts_hierarchy = _create_nuts3_hierarchy() | ||
"""Hierarchical dictionary of nuts region classification""" | ||
|
||
|
||
subannual = _parse_yaml(DEF_PATH / 'subannual') | ||
"""Dictionary of subannual timeslices""" | ||
|
||
|
||
def validate(df): | ||
"""Validate that all columns of a dataframe follow the nomenclature | ||
Parameters | ||
---------- | ||
df : path to file, pandas.DataFrame, pyam.IamDataFrame (or castable object) | ||
A timeseries dataframe following the common data format | ||
Returns | ||
------- | ||
bool | ||
Return `True` if all column entries in `df` are valid | ||
or `False` otherwise | ||
""" | ||
df = IamDataFrame(df) | ||
success = True | ||
|
||
# set up list of dimension (columns) to validate | ||
cols = [ | ||
('region', regions, 's'), | ||
('variable', variables, 's') | ||
] | ||
if 'subannual' in df.data.columns: | ||
cols.append(('subannual', subannual, ' timeslices')) | ||
|
||
# iterate over dimensions and perform validation | ||
msg = 'The following {} are not defined in the nomenclature:\n {}' | ||
for col, codelist, ext in cols: | ||
invalid = [c for c in df.data[col].unique() if c not in codelist] | ||
if invalid: | ||
success = False | ||
logger.warning(msg.format(col + ext, invalid)) | ||
|
||
return success |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Default entry for the subannual column | ||
|
||
Year: | ||
duration: 1 |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import nomenclature as nc | ||
|
||
|
||
def test_variables(): | ||
# check that regions dictionary is not empty and has specific element | ||
assert 'Emissions|CO2' in nc.variables | ||
|
||
|
||
def test_regions(): | ||
# check that regions dictionary is not empty and has specific element | ||
assert 'Europe' in nc.regions | ||
|
||
|
||
def test_iso_mapping(): | ||
# check that iso-mapping dictionary is not empty and has specific elements | ||
for name in ['GR', 'GRC', 'EL']: | ||
assert nc.iso_mapping[name] == 'Greece' | ||
|
||
|
||
def test_nuts_hierarchy(): | ||
# check that nuts-hierarchy is not empty and has specific elements | ||
assert nc.nuts_hierarchy['Belgium']['BE2']['BE24'] == ['BE241', 'BE242'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
pyyaml | ||
pyam-iamc # the pyam package is released on pypi under this name |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
[metadata] | ||
name = nomenclature | ||
author = openENTRANCE consortium | ||
author_email = [email protected] | ||
license = Apache License 2.0 | ||
description = Model linkage nomenclature for the openENTRANCE project | ||
long_description = file: README.md | ||
long_description_content_type = text/x-md | ||
url = https://github.com/openENTRANCE/nomenclature | ||
|
||
[options] | ||
packages = nomenclature | ||
include_package_data = True | ||
install_requires = | ||
setuptools >= 41 | ||
pyyaml | ||
setup_requires = | ||
setuptools >= 41 | ||
setuptools_scm | ||
|
||
[options.package_data] | ||
iam_units = | ||
nomenclature/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from setuptools import setup | ||
|
||
setup(use_scm_version=True) |