Source code for arkimet.formatter.eccodes
import os
import re
[docs]def get_eccodes_def_dir() -> str:
"""
get the list of directories (separated by :) where grib_api/eccodes keep their definitions
"""
path = os.environ.get("ECCODES_DEFINITION_PATH", None)
if path is not None:
return path.split(":")
path = os.environ.get("GRIBAPI_DEFINITION_PATH", None)
if path is not None:
return path.split(":")
return ["/usr/share/eccodes/definitions/"]
[docs]class GribTable:
"""
Read a grib table.
edition is the GRIB edition: 1 or 2
table is the table name, for example "0.0"
Returns a table where the index maps to a couple { abbreviation, description },
or nil if the file had no such entry.
For convenience, the table has also two functions, 'abbr' and 'desc', that
return the abbreviation or the description, falling back on returning the table
index if they are not available.
For example:
origins = GribTable(1, "0")
print(origins.abbr(98)) -- Prints 'ecmf'
print(origins.desc(98)) -- Prints 'European Center for Medium-Range Weather Forecasts'
print(origins.abbr(999)) -- Prints '999'
print(origins.desc(999)) -- Prints '999'
"""
cache = {}
re_table_line = re.compile(r"^\s*(?P<idx>\d+)\s+(?P<abbr>\S+)\s+(?P<desc>.+)$")
def __init__(self, edition: int, table: str):
self.edition = edition
self.table = table
self._abbr = {}
self._desc = {}
for path in get_eccodes_def_dir():
# Build the file name
fname = os.path.join(path, "grib" + str(edition), str(table)) + ".table"
try:
with open(fname, "rt") as fd:
for line in fd:
mo = self.re_table_line.match(line)
if not mo:
continue
idx = int(mo.group("idx"))
self._abbr[idx] = mo.group("abbr")
self._desc[idx] = mo.group("desc").strip()
except FileNotFoundError:
pass
else:
break
[docs] def set(self, code: int, abbr: str, desc: str):
"""
Add/replace a value in the table
"""
self._abbr[code] = abbr
self._desc[code] = desc
[docs] def has(self, val: int) -> bool:
return val in self._abbr
[docs] def abbr(self, val: int) -> str:
"""
Get an abbreviated description
"""
res = self._abbr.get(val)
if res is None:
return str(val)
else:
return res
[docs] def desc(self, val: int) -> str:
"""
Get a long description
"""
res = self._desc.get(val)
if res is None:
return str(val)
else:
return res
[docs] @classmethod
def load(cls, edition: int, table: str) -> "GribTable":
key = (edition, table)
res = cls.cache.get(key)
if res is None:
res = cls(edition, table)
cls.cache[key] = res
return res
[docs] @classmethod
def get_grib2_table_prefix(cls, centre, table_version, local_table_version):
default_table_version = 4
if table_version is None or table_version == 255:
table_version = default_table_version
if local_table_version is not None and local_table_version not in (0, 255):
centres = cls.load(1, "0")
if centres.has(centre):
return os.path.join('tables', 'local', centres.abbr(centre), str(local_table_version))
return os.path.join('tables', str(table_version))