Commit 6f87ac7f authored by Klaus Zimmermann's avatar Klaus Zimmermann
Browse files

Templated index generation (closes #47)

parent e697f0ee
from .main import main
from .._version import get_versions
__version__ = get_versions()['version']
del get_versions
__all__ = [
'__version__',
'main',
]
# -*- coding: utf-8 -*-
import argparse
import pprint
from jinja2 import Environment, PackageLoader
import pyexcel as pe
import climix
from .mastertable import build_index_definitions
def prepare_environment(args):
loader = PackageLoader('climix.editor')
env = Environment(loader=loader, trim_blocks=True)
return env
def parse_args():
parser = argparse.ArgumentParser(
description=('An editor for a climate index thing, version {}.'
''.format(climix.__version__)))
parser.add_argument('-o', '--output')
parser.add_argument('master_table')
return parser.parse_args()
def main():
args = parse_args()
env = prepare_environment(args)
template = env.get_template('index_definitions.yml')
output = template.render(indices=build_index_definitions(args.master_table))
if args.output is None:
print(output)
else:
with open(args.output, 'w') as outfile:
outfile.write(output)
# -*- coding: utf-8 -*-
import pyexcel as pe
def build_periods(spec):
PERIODS = {
'ann': 'annual',
'sea': 'seasonal',
'mon': 'monthly',
'_': 'unknown',
'': 'unknown',
}
periods = [PERIODS[period] for period in spec.split('/')]
return periods
INDEX_FUNCTIONS = {
'FUN_count': 'count_occurrences',
'FUN_spell': 'spell_length',
}
def split_parts(no_parts, part_string):
parts = [p.strip() for p in part_string.split(',')]
assert len(parts) == no_parts
return parts
def tr_inputs(no_inputs,
variable_string, standard_name_string, cell_method_string):
variables = split_parts(no_inputs, variable_string)
standard_names = split_parts(no_inputs, standard_name_string)
cell_methods = split_parts(no_inputs, cell_method_string)
d = []
for vn, sn, cm in zip(variables, standard_names, cell_methods):
d.append({'var_name': vn,
'standard_name': sn,
'cell_methods': cm})
return d
def tr_relops(no_thresholds, relop_string):
relops = split_parts(no_thresholds, relop_string)
d = [{'var_name': 'relop_{}'.format(i),
'kind': 'operator',
'operator': '"{}"'.format(relop)}
for i, relop in enumerate(relops)
]
return d
def tr_index_function(name, no_thresholds,
var_name_string, standard_name_string,
value_string, units_string, relop_string):
var_names = split_parts(no_thresholds, var_name_string)
standard_names = split_parts(no_thresholds, standard_name_string)
values = split_parts(no_thresholds, value_string)
units = split_parts(no_thresholds, units_string)
parameters = []
for vn, sn, v, u in zip(var_names, standard_names, values, units):
parameters.append({
'var_name': vn,
'kind': 'quantity',
'standard_name': sn,
'data': v,
'units': u,
})
relops = tr_relops(no_thresholds, relop_string)
parameters.extend(relops)
index_function = {
'name': INDEX_FUNCTIONS.get(name, name),
'parameters': parameters,
}
return index_function
def prepare_record(record):
var_name = record['VarName']
no_thresholds = int(record['N_thresholds'])
no_inputs = int(record['N_inputs'])
d = {
'var_name': var_name,
'reference': record['OUTPUT_reference'],
'period': {'allowed': build_periods(record['freq']),
'default': build_periods(record['default_freq'])[0],},
'output': {
'var_name': var_name,
'standard_name': record['OUTPUT_standard_name'],
'long_name': record['OUTPUT_long_name'],
'cell_methods': record['OUTPUT_cell_methods'],
'units': record['OUTPUT_units'],
},
'inputs': tr_inputs(no_inputs,
record['INPUT_variable'],
record['INPUT_standard_name'],
record['INPUT_cell_methods']),
'index_function': tr_index_function(
record['index_function'],
no_thresholds,
record['THRESHOLD_VarName'], record['THRESHOLD_standard_name'],
record['THRESHOLD_value'], record['THRESHOLD_units'],
record['THRESHOLD_relop']),
'ET': {
'short_name': record['ET_short_name'],
'long_name': record['ET_long_name'],
'definition': record['ET_definition'],
'comment': record['ET_comment'],
}
}
proposed_standard_name = record['OUTPUT_proposed_standard_name']
if proposed_standard_name.strip() != '':
d['output']['proposed_standard_name'] = proposed_standard_name
return d
def build_index_definitions(file_name):
sheet = pe.get_sheet(file_name=file_name,
sheet_name='index attr')
sheet.name_columns_by_row(0)
records = sheet.to_records()
index_definitions = []
for record in records:
try:
index_definitions.append(prepare_record(record))
except:
pass
return index_definitions
indices:
{% for idx in indices %}
{{ idx.var_name }}:
reference: ETCCDI
period:
allowed:
{% for p in idx.period.allowed %}
{{ p }}:
{% endfor %}
default: {{ idx.period.default }}
output:
var_name: {{ idx.output.var_name }}
standard_name: {{ idx.output.standard_name }}
{% if idx.output.proposed_standard_name %}
proposed_standard_name: {{ idx.output.proposed_standard_name }}
{% endif %}
long_name: {{ idx.output.long_name }}
units: {{ idx.output.units }}
# cell_methods: {{ idx.output.cell_methods }}
input:
{% for input in idx.inputs %}
var_name: {{ input.var_name }}
standard_name: {{ input.standard_name }}
# cell_methods: {{ input.cell_methods }}
{% endfor %}
index_function:
name: {{ idx.index_function.name }}
parameters:
{% for param in idx.index_function.parameters %}
{% if param.kind == 'quantity' %}
{{ param.var_name }}:
kind: {{ param.kind }}
standard_name: {{ param.standard_name }}
data: {{ param.data }}
units: {{ param.units }}
{% elif param.kind == 'operator' %}
{{ param.var_name }}:
kind: {{ param.kind }}
operator: {{ param.operator }}
{% endif %}
{% endfor %}
ET:
short_name: {{ idx.ET.short_name }}
long_name: {{ idx.ET.long_name }}
definition: {{ idx.ET.definition }}
comment: {{ idx.ET.comment }}
{% endfor %}
......@@ -40,9 +40,13 @@ setuptools.setup(
'numpy',
'PyYAML',
],
extras_require={
'editor': ['pyexcel', 'pyexcel-odsr', 'jinja2']
},
entry_points={
'console_scripts': [
'climix=climix:main',
'climix-editor=climix.editor:main [editor]',
],
'climix.index_functions': [
'count_occurrences=climix.index_functions:CountOccurences',
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment