Skip to content

Commit a9bfebc

Browse files
authored
Merge pull request #649 from ESMValGroup/version2_provenance
Version 2: Provenance tracking
2 parents 8e417d8 + b9a4301 commit a9bfebc

File tree

71 files changed

+3172
-1435
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+3172
-1435
lines changed

.circleci/config.yml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,6 @@ jobs:
3939
path: test-reports/
4040
- store_artifacts:
4141
path: test-reports/
42-
- run:
43-
# Upload Python 3 test coverage to codacy, even when the actual
44-
# running of the tests fails.
45-
when: always
46-
command: |
47-
pip install codacy-coverage
48-
python-codacy-coverage -r test-reports/python3/coverage.xml
4942

5043
python2_test:
5144
# Run Python 2 tests
@@ -119,6 +112,15 @@ jobs:
119112
ncl -V
120113
- store_artifacts:
121114
path: /logs
115+
- store_artifacts:
116+
path: test-reports/
117+
- store_test_results:
118+
path: test-reports/
119+
- run:
120+
when: always
121+
command: |
122+
pip install codacy-coverage
123+
python-codacy-coverage -r test-reports/python3/coverage.xml
122124
123125
python2_install:
124126
# Test Python 2 installation

environment.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ channels:
77
dependencies:
88
# Python packages that cannot be installed from PyPI:
99
- iris=1.13
10+
- graphviz
1011
- matplotlib<3
1112
- python-stratify
1213
- esmpy

esmvaltool/_config.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def read_config_user_file(config_file, recipe_name):
4848

4949
for key in defaults:
5050
if key not in cfg:
51-
logger.warning(
51+
logger.info(
5252
"No %s specification in config file, "
5353
"defaulting to %s", key, defaults[key])
5454
cfg[key] = defaults[key]
@@ -94,10 +94,9 @@ def get_config_user_file():
9494

9595

9696
def _normalize_path(path):
97-
"""
98-
Normalize paths.
97+
"""Normalize paths.
9998
100-
Expand ~ character and environment variables and convert path to absolute
99+
Expand ~ character and environment variables and convert path to absolute.
101100
102101
Parameters
103102
----------
@@ -154,6 +153,7 @@ def configure_logging(cfg_file=None, output=None, console_log_level=None):
154153

155154
logging.config.dictConfig(cfg)
156155
logging.Formatter.converter = time.gmtime
156+
logging.captureWarnings(True)
157157

158158
return log_files
159159

@@ -182,3 +182,34 @@ def replace_mip_fx(fx_file):
182182
new_mip = CFG['CMIP5']['fx_mip_change'].get(fx_file, default_mip)
183183
logger.debug("Switching mip for fx file finding to %s", new_mip)
184184
return new_mip
185+
186+
187+
TAGS_CONFIG_FILE = os.path.join(
188+
os.path.dirname(__file__), 'config-references.yml')
189+
190+
191+
def _load_tags(filename=TAGS_CONFIG_FILE):
192+
"""Load the refence tags used for provenance recording."""
193+
logger.debug("Loading tags from %s", filename)
194+
with open(filename) as file:
195+
return yaml.safe_load(file)
196+
197+
198+
TAGS = _load_tags()
199+
200+
201+
def get_tag_value(section, tag):
202+
"""Retrieve the value of a tag."""
203+
if section not in TAGS:
204+
raise ValueError("Section '{}' does not exist in {}".format(
205+
section, TAGS_CONFIG_FILE))
206+
if tag not in TAGS[section]:
207+
raise ValueError(
208+
"Tag '{}' does not exist in section '{}' of {}".format(
209+
tag, section, TAGS_CONFIG_FILE))
210+
return TAGS[section][tag]
211+
212+
213+
def replace_tags(section, tags):
214+
"""Replace a list of tags with their values."""
215+
return tuple(get_tag_value(section, tag) for tag in tags)

esmvaltool/_data_finder.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
import six
1313

14-
from ._config import get_institutes, get_project_config, replace_mip_fx
14+
from ._config import get_project_config, replace_mip_fx
1515
from .cmor.table import CMOR_TABLES
1616

1717
logger = logging.getLogger(__name__)
@@ -242,7 +242,6 @@ def _find_input_files(variable, rootpath, drs, fx_var=None):
242242

243243
def get_input_filelist(variable, rootpath, drs):
244244
"""Return the full path to input files."""
245-
variable['institute'] = get_institutes(variable)
246245
files = _find_input_files(variable, rootpath, drs)
247246
files = select_files(files, variable['start_year'], variable['end_year'])
248247
return files
@@ -258,7 +257,6 @@ def get_input_fx_filelist(variable, rootpath, drs):
258257
var['frequency'] = table.frequency
259258
realm = getattr(table.get(var['short_name']), 'modeling_realm', None)
260259
var['modeling_realm'] = realm if realm else table.realm
261-
var['institute'] = get_institutes(variable)
262260

263261
files = _find_input_files(var, rootpath, drs, fx_var)
264262
fx_files[fx_var] = files[0] if files else None
@@ -272,23 +270,23 @@ def get_output_file(variable, preproc_dir):
272270

273271
outfile = os.path.join(
274272
preproc_dir,
275-
'{diagnostic}_{preprocessor}_{short_name}'.format(**variable),
276-
_replace_tags(cfg['output_file'], variable)[0] + '.nc')
273+
variable['diagnostic'],
274+
variable['variable_group'],
275+
_replace_tags(cfg['output_file'], variable)[0] + '.nc',
276+
)
277277

278278
return outfile
279279

280280

281-
def get_statistic_output_file(variable, statistic, preproc_dir):
281+
def get_statistic_output_file(variable, preproc_dir):
282282
"""Get multi model statistic filename depending on settings."""
283-
values = dict(variable)
284-
values['stat'] = statistic.title()
285-
286283
template = os.path.join(
287284
preproc_dir,
288-
'{diagnostic}_{preprocessor}_{short_name}',
289-
'MultiModel{stat}_{field}_{short_name}_{start_year}-{end_year}.nc',
285+
'{diagnostic}',
286+
'{variable_group}',
287+
'{dataset}_{field}_{short_name}_{start_year}-{end_year}.nc',
290288
)
291289

292-
outfile = template.format(**values)
290+
outfile = template.format(**variable)
293291

294292
return outfile

esmvaltool/_main.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
Benjamin Mueller (LMU, Germany - [email protected])
1313
Valeriu Predoi (URead, UK - [email protected])
1414
Mattia Righi (DLR, Germany - [email protected])
15+
Manuel Schlund (DLR, Germany - [email protected])
1516
Javier Vegas-Regidor (BSC, Spain - [email protected])
1617
1718
For further help, please read the documentation at
@@ -39,7 +40,7 @@
3940

4041
from . import __version__
4142
from ._config import configure_logging, read_config_user_file
42-
from ._recipe import read_recipe_file
43+
from ._recipe import read_recipe_file, TASKSEP
4344
from ._task import resource_usage_logger
4445

4546
# set up logging
@@ -89,6 +90,14 @@ def get_args():
8990
'--max-years',
9091
type=int,
9192
help='Limit the number of years to MAX_YEARS.')
93+
parser.add_argument(
94+
'--skip-nonexistent',
95+
action='store_true',
96+
help="Skip datasets that cannot be found.")
97+
parser.add_argument(
98+
'--diagnostics',
99+
nargs='*',
100+
help="Only run the named diagnostics from the recipe.")
92101
args = parser.parse_args()
93102
return args
94103

@@ -129,6 +138,11 @@ def main(args):
129138
logger.info("Using config file %s", config_file)
130139
logger.info("Writing program log files to:\n%s", "\n".join(log_files))
131140

141+
cfg['skip-nonexistent'] = args.skip_nonexistent
142+
cfg['diagnostics'] = {
143+
pattern if TASKSEP in pattern else pattern + TASKSEP + '*'
144+
for pattern in args.diagnostics or ()
145+
}
132146
cfg['synda_download'] = args.synda_download
133147
for limit in ('max_datasets', 'max_years'):
134148
value = getattr(args, limit)
@@ -221,6 +235,11 @@ def run():
221235
"Program terminated abnormally, see stack trace "
222236
"below for more information",
223237
exc_info=True)
238+
logger.info(
239+
"If you suspect this is a bug or need help, please open an issue "
240+
"on https://github.com/ESMValGroup/ESMValTool/issues and attach "
241+
"the run/recipe_*.yml and run/main_log_debug.txt files from the "
242+
"output directory.")
224243
sys.exit(1)
225244
else:
226245
if conf["remove_preproc_dir"]:

0 commit comments

Comments
 (0)