diff --git a/deploy/conda-dev-spec.template b/deploy/conda-dev-spec.template index 2f1bd11331..8710629ac1 100644 --- a/deploy/conda-dev-spec.template +++ b/deploy/conda-dev-spec.template @@ -6,6 +6,7 @@ cmocean esmf={{ esmf }}={{ mpi_prefix }}_* ffmpeg geometric_features={{ geometric_features }} +gsw importlib_resources ipython jupyter @@ -33,6 +34,7 @@ requests ruamel.yaml scipy>=1.8.0 shapely>=2.0,<3.0 +tranche>=0.3.0 xarray # Static typing diff --git a/docs/conf.py b/docs/conf.py index ff52ec8980..f8e0d7fa43 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -76,7 +76,8 @@ 'python': ('https://docs.python.org', None), 'scipy': ('https://docs.scipy.org/doc/scipy/reference', None), "sphinx": ("https://www.sphinx-doc.org/en/master", None), - 'xarray': ('https://xarray.pydata.org/en/stable', None) + 'xarray': ('https://xarray.pydata.org/en/stable', None), + 'tranche': ('https://xylar.github.io/tranche/', None), } # -- MyST settings --------------------------------------------------- diff --git a/docs/developers_guide/framework/config.md b/docs/developers_guide/framework/config.md index 59d98d9241..8e3a686235 100644 --- a/docs/developers_guide/framework/config.md +++ b/docs/developers_guide/framework/config.md @@ -2,10 +2,10 @@ # Config files -The primary documentation for the config parser is in -[MPAS-Tools config parser](http://mpas-dev.github.io/MPAS-Tools/stable/config.html). +The primary documentation for the config parser is in the +[tranche documentation](https://xylar.github.io/tranche/). Here, we include some specific details relevant to using the -{py:class}`mpas_tools.config.MpasConfigParser` in polaris. +{py:class}`tranche.Tranche` in polaris. Here, we provide the {py:class}`polaris.config.PolarisConfigParser` that has almost the same functionality but also ensures that certain relative paths are @@ -18,7 +18,7 @@ options) as part of setting up polaris tasks and steps. These features are included to accommodate sharing config options across shared steps and/or multiple tasks. -The {py:meth}`mpas_tools.config.MpasConfigParser.add_from_package()` method can +The {py:meth}`tranche.Tranche.add_from_package()` method can be used to add the contents of a config file within a package to the config options. Examples of this can be found in many tasks as well as in the `polaris.setup` module. Here is a typical example from @@ -71,11 +71,12 @@ for use by the framework rather than individual tasks. Other methods for the `MpasConfigParser` are similar to those for {py:class}`configparser.ConfigParser`. In addition to `get()`, `getinteger()`, `getfloat()` and `getboolean()` methods, this class -implements {py:meth}`mpas_tools.config.MpasConfigParser.getlist()`, which +implements {py:meth}`tranche.Tranche.getlist()`, which can be used to parse a config value separated by spaces and/or commas into -a list of strings, floats, integers, booleans, etc. Another useful method -is {py:meth}`mpas_tools.config.MpasConfigParser.getexpression()`, which can -be used to get python dictionaries, lists and tuples as well as a small set +a list of strings, floats, integers, booleans, etc. Other useful methods +are {py:meth}`tranche.Tranche.getexpression()`, which can +be used to get python dictionaries, lists, and tuples, and +{py:meth}`tranche.Tranche.getnumpy()`, which also suppports a small set of functions (`range()`, {py:meth}`numpy.linspace()`, {py:meth}`numpy.arange()`, and {py:meth}`numpy.array()`) @@ -182,9 +183,10 @@ class Rpe(Task): ## Comments in config files -One of the main advantages of {py:class}`mpas_tools.config.MpasConfigParser` +One of the main advantages of {py:class}`tranche.Tranche` over {py:class}`configparser.ConfigParser` is that it keeps track of comments that are associated with config sections and options. -See [comments in config files](http://mpas-dev.github.io/MPAS-Tools/stable/config.html#config_comments) -in MPAS-Tools for more details. +Comments must begin with the `#` character. They must be placed *before* the +config section or option in question (preferably without blank lines between). +The comments can be any number of lines long. diff --git a/polaris/config.py b/polaris/config.py index a80bb19674..75ab09c0d3 100644 --- a/polaris/config.py +++ b/polaris/config.py @@ -1,10 +1,10 @@ import os from typing import Union -from mpas_tools.config import MpasConfigParser +from tranche import Tranche -class PolarisConfigParser(MpasConfigParser): +class PolarisConfigParser(Tranche): """ A "meta" config parser that keeps a dictionary of config parsers and their sources to combine when needed. The custom config parser allows provenance diff --git a/polaris/job/__init__.py b/polaris/job/__init__.py index 2ce8e74548..e2acc9754a 100644 --- a/polaris/job/__init__.py +++ b/polaris/job/__init__.py @@ -244,7 +244,9 @@ def _get_job_options( wall_time : str filesystems : str """ - partition_or_queue = config.get('job', partition_or_queue_option) + par_section = config['parallel'] + job_section = config['job'] + partition_or_queue = job_section.get(partition_or_queue_option) if partition_or_queue == '<<>>': if machine == 'anvil' and partition_or_queue == 'partition': # choose the partition based on the number of nodes @@ -254,37 +256,35 @@ def _get_job_options( partition_or_queue = 'acme-medium' else: partition_or_queue = 'acme-large' - elif config.has_option('parallel', partitions_or_queues): + elif par_section.has_option(partitions_or_queues): # get the first, which is the default - partition_or_queue = config.getlist( - 'parallel', partitions_or_queues - )[0] + partition_or_queue = par_section.getlist(partitions_or_queues)[0] else: partition_or_queue = '' - qos = config.get('job', 'qos') + qos = job_section.get('qos') if qos == '<<>>': - if config.has_option('parallel', 'qos'): - qos = config.getlist('parallel', 'qos')[0] + if par_section.has_option('qos'): + qos = par_section.getlist('qos')[0] else: qos = '' - constraint = config.get('job', 'constraint') + constraint = job_section.get('constraint') if constraint == '<<>>': - if config.has_option('parallel', 'constraints'): - constraint = config.getlist('parallel', 'constraints')[0] + if par_section.has_option('constraints'): + constraint = par_section.getlist('constraints')[0] else: constraint = '' - if config.has_option('parallel', 'gpus_per_node'): - gpus_per_node = config.get('parallel', 'gpus_per_node') + if par_section.has_option('gpus_per_node'): + gpus_per_node = par_section.get('gpus_per_node') else: gpus_per_node = '' - wall_time = config.get('job', 'wall_time') + wall_time = job_section.get('wall_time') - if config.has_option('job', 'filesystems'): - filesystems = config.get('job', 'filesystems') + if job_section.has_option('filesystems'): + filesystems = job_section.get('filesystems') else: filesystems = '' diff --git a/polaris/ocean/model/ocean_model_step.py b/polaris/ocean/model/ocean_model_step.py index 0dfd9da21c..8353681263 100644 --- a/polaris/ocean/model/ocean_model_step.py +++ b/polaris/ocean/model/ocean_model_step.py @@ -303,13 +303,14 @@ def update_namelist_eos(self): Modify the namelist to make it consistent with eos config options """ config = self.config - - eos_type = config.get('ocean', 'eos_type') - eos_linear_alpha = config.getfloat('ocean', 'eos_linear_alpha') - eos_linear_beta = config.getfloat('ocean', 'eos_linear_beta') - eos_linear_rhoref = config.getfloat('ocean', 'eos_linear_rhoref') - eos_linear_Tref = config.getfloat('ocean', 'eos_linear_Tref') - eos_linear_Sref = config.getfloat('ocean', 'eos_linear_Sref') + section = config['ocean'] + + eos_type = section.get('eos_type') + eos_linear_alpha = section.getfloat('eos_linear_alpha') + eos_linear_beta = section.getfloat('eos_linear_beta') + eos_linear_rhoref = section.getfloat('eos_linear_rhoref') + eos_linear_Tref = section.getfloat('eos_linear_Tref') + eos_linear_Sref = section.getfloat('eos_linear_Sref') replacements = { 'config_eos_type': eos_type, diff --git a/polaris/version.py b/polaris/version.py index 23a1c76177..7032ae6d75 100644 --- a/polaris/version.py +++ b/polaris/version.py @@ -1 +1 @@ -__version__ = '0.9.0-alpha.3' +__version__ = '0.9.0-alpha.4' diff --git a/polaris/viz/spherical.py b/polaris/viz/spherical.py index 116f5cebf7..d3412f2c4e 100644 --- a/polaris/viz/spherical.py +++ b/polaris/viz/spherical.py @@ -326,9 +326,11 @@ def _setup_colormap(config, colormap_section): colormap = plt.get_cmap(config.get(colormap_section, 'colormap_name')) - norm_type = config.get(colormap_section, 'norm_type') + section = config[colormap_section] - kwargs = config.getexpression(colormap_section, 'norm_args') + norm_type = section.get('norm_type') + + kwargs = section.getnumpy('norm_args') if norm_type == 'symlog': norm = cols.SymLogNorm(**kwargs) @@ -342,17 +344,15 @@ def _setup_colormap(config, colormap_section): ) try: - ticks = config.getexpression( - colormap_section, 'colorbar_ticks', use_numpyfunc=True - ) + ticks = section.getnumpy('colorbar_ticks') except configparser.NoOptionError: ticks = None - if config.has_option(colormap_section, 'under_color'): - under_color = config.get(colormap_section, 'under_color') + if section.has_option('under_color'): + under_color = section.get('under_color') colormap.set_under(under_color) - if config.has_option(colormap_section, 'over_color'): - over_color = config.get(colormap_section, 'over_color') + if section.has_option('over_color'): + over_color = section.get('over_color') colormap.set_over(over_color) return colormap, norm, ticks diff --git a/pyproject.toml b/pyproject.toml index 58c081e461..5f3e8049ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,7 @@ classifiers = [ dependencies = [ "cartopy", "cmocean", + "gsw", "importlib_resources", "ipython", "jigsawpy", @@ -45,6 +46,7 @@ dependencies = [ "requests", "scipy>=1.8.0", "shapely>=2.0,<3.0", + "tranche>=0.3.0", "xarray", ]