Skip to content

Commit

Permalink
Merge cd589d5 into 3b2a455
Browse files Browse the repository at this point in the history
  • Loading branch information
IanVermes committed Dec 3, 2019
2 parents 3b2a455 + cd589d5 commit e0c8218
Show file tree
Hide file tree
Showing 25 changed files with 718 additions and 447 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Expand Up @@ -3,6 +3,9 @@ __pycache__/
*.py[cod]
*$py.class

# Static typed files
.pytype

# C extensions
*.so

Expand Down Expand Up @@ -76,4 +79,4 @@ venv.bak/
.docker-tox/
tests/sample-data/cds*.grib
tests/sample-data/cds*.nc
*.idx
*.idx
11 changes: 6 additions & 5 deletions .travis.yml
Expand Up @@ -5,8 +5,8 @@ sudo: false # use container based build
matrix:
fast_finish: true
include:
- env: ENV=py36
- env: ENV=py37
- env: ENV=py36
- env: ENV=py37

before_install:
- wget http://repo.continuum.io/miniconda/Miniconda3-3.16.0-Linux-x86_64.sh -O miniconda.sh;
Expand All @@ -24,15 +24,16 @@ install:
- pip install --no-deps -e .

script:
- black --check .
- which python
- python --version
- python -c "import eccodes"
- if [[ "$ENV" == "docs" ]]; then
sphinx-build -W -b html docs build/sphinx/html;
sphinx-build -W -b html docs build/sphinx/html;
elif [[ "$ENV" == *"-qc" ]]; then
pytest -v --flakes --doctest-glob="*.rst" --cov=eccodes --cov=gribapi --cov-report term-missing --pep8 --mccabe $EXTRA_FLAGS;
pytest -v --flakes --doctest-glob="*.rst" --cov=eccodes --cov=gribapi --cov-report term-missing --pep8 --mccabe $EXTRA_FLAGS;
else
pytest -v --cov=eccodes --cov=gribapi --cov-report term-missing $EXTRA_FLAGS;
pytest -v --cov=eccodes --cov=gribapi --cov-report term-missing $EXTRA_FLAGS;
fi

after_success:
Expand Down
10 changes: 7 additions & 3 deletions CONTRIBUTING.rst
Expand Up @@ -8,7 +8,7 @@ Contributing
Contributions are welcome, and they are greatly appreciated! Every
little bit helps, and credit will always be given.

Please note, that we have hooked a CLA assiatant to this GitHub Repo. Please accept the contributors license agreement to allow us to keep a legal track of contributions and keep this package open source for the future.
Please note, that we have hooked a CLA assiatant to this GitHub Repo. Please accept the contributors license agreement to allow us to keep a legal track of contributions and keep this package open source for the future.

You can contribute in many ways:

Expand Down Expand Up @@ -82,13 +82,17 @@ you already have `virtualenv` and `Git` installed and ready to go.

8. If your contribution is a bug fix or new feature, you should add a test to the existing test suite.

9. Commit your changes and push your branch to GitHub::
9. Format your Python code with the Black auto-formatter, to ensure the code is uses the library's style. We use the default Black configuration (88 lines per character and `"` instead of `'` for string encapsulation)::

$ black .

10. Commit your changes and push your branch to GitHub::

$ git add .
$ git commit -m "Your detailed description of your changes."
$ git push origin name-of-your-bugfix-or-feature

10. Submit a pull request through the GitHub website.
11. Submit a pull request through the GitHub website.

Pull Request Guidelines
-----------------------
Expand Down
9 changes: 2 additions & 7 deletions builder.py
Expand Up @@ -5,14 +5,9 @@

ffibuilder = cffi.FFI()
ffibuilder.set_source(
"gribapi._bindings",
'#include <eccodes.h>',
libraries=["eccodes"],
)
ffibuilder.cdef(
open("gribapi/grib_api.h").read() +
open("gribapi/eccodes.h").read()
"gribapi._bindings", "#include <eccodes.h>", libraries=["eccodes"],
)
ffibuilder.cdef(open("gribapi/grib_api.h").read() + open("gribapi/eccodes.h").read())

if __name__ == "__main__":
try:
Expand Down
1 change: 1 addition & 0 deletions ci/requirements-dev.txt
Expand Up @@ -11,3 +11,4 @@ tox
tox-pyenv
wheel
zest.releaser
black
1 change: 1 addition & 0 deletions ci/requirements-py36-qc.yml
Expand Up @@ -15,3 +15,4 @@ dependencies:
- pytest-pep8
- python=3.6
- typing
- black
1 change: 1 addition & 0 deletions ci/requirements-py36.yml
Expand Up @@ -12,3 +12,4 @@ dependencies:
- pytest-cov
- python=3.6
- typing
- black
1 change: 1 addition & 0 deletions ci/requirements-py37.yml
Expand Up @@ -13,3 +13,4 @@ dependencies:
- pytest-flakes
- python=3.7
- typing
- black
22 changes: 11 additions & 11 deletions docs/conf.py
Expand Up @@ -17,22 +17,22 @@

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode"]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]

# The suffix of source filenames.
source_suffix = '.rst'
source_suffix = ".rst"

# The encoding of source files.
# source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'
master_doc = "index"

# General information about the project.
project = u'eccodes-python'
project = u"eccodes-python"
copyright = u"2017-2019, European Centre for Medium-Range Weather Forecasts (ECMWF)."

# The version info for the project you're documenting, acts as replacement
Expand All @@ -42,7 +42,7 @@
# The full version, including alpha/beta/rc tags.
release = pkg_resources.get_distribution("eccodes-python").version
# The short X.Y version.
version = '.'.join(release.split('.')[:2])
version = ".".join(release.split(".")[:2])

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand All @@ -56,7 +56,7 @@

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
exclude_patterns = ["_build"]

# The reST default role (used for this markup: `text`) to use for all
# documents.
Expand All @@ -74,7 +74,7 @@
# show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = "sphinx"

# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
Expand All @@ -88,7 +88,7 @@

# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
html_theme = "default"

# Theme options are theme-specific and customize the look and feel of a
# theme further. For a list of options available for each theme, see the
Expand Down Expand Up @@ -119,7 +119,7 @@
# here, relative to this directory. They are copied after the builtin
# static files, so a file named "default.css" will overwrite the builtin
# "default.css".
html_static_path = ['_static']
html_static_path = ["_static"]

# If not '', a 'Last updated on:' timestamp is inserted at every page
# bottom, using the given strftime format.
Expand Down Expand Up @@ -165,4 +165,4 @@
# html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'cfgribdoc'
htmlhelp_basename = "cfgribdoc"
10 changes: 6 additions & 4 deletions eccodes/__main__.py
Expand Up @@ -29,13 +29,15 @@ def selfcheck():

def main(argv=None):
parser = argparse.ArgumentParser()
parser.add_argument('command')
parser.add_argument("command")
args = parser.parse_args(args=argv)
if args.command == 'selfcheck':
if args.command == "selfcheck":
selfcheck()
else:
raise RuntimeError("Command not recognised %r. See usage with --help." % args.command)
raise RuntimeError(
"Command not recognised %r. See usage with --help." % args.command
)


if __name__ == '__main__': # pragma: no cover
if __name__ == "__main__": # pragma: no cover
main()
38 changes: 19 additions & 19 deletions eccodes/high_level/bufr.py
Expand Up @@ -16,33 +16,31 @@
class BufrMessage(CodesMessage):

__doc__ = "\n".join(CodesMessage.__doc__.splitlines()[4:]).format(
prod_type="BUFR", classname="BufrMessage", parent="BufrFile",
alias="bufr")
prod_type="BUFR", classname="BufrMessage", parent="BufrFile", alias="bufr"
)

product_kind = eccodes.CODES_PRODUCT_BUFR

# Arguments included explicitly to support introspection
# TODO: Can we get this to work with an index?
def __init__(self, codes_file=None, clone=None, sample=None,
headers_only=False):
def __init__(self, codes_file=None, clone=None, sample=None, headers_only=False):
"""
Open a message and inform the GRIB file that it's been incremented.
The message is taken from ``codes_file``, cloned from ``clone`` or
``sample``, or taken from ``index``, in that order of precedence.
"""
super(self.__class__, self).__init__(codes_file, clone, sample,
headers_only)
#self._unpacked = False
super(self.__class__, self).__init__(codes_file, clone, sample, headers_only)
# self._unpacked = False

#def get(self, key, ktype=None):
# def get(self, key, ktype=None):
# """Return requested value, unpacking data values if necessary."""
# # TODO: Only do this if accessing arrays that need unpacking
# if not self._unpacked:
# self.unpacked = True
# return super(self.__class__, self).get(key, ktype)

#def missing(self, key):
# def missing(self, key):
# """
# Report if key is missing.#
#
Expand All @@ -52,15 +50,15 @@ def __init__(self, codes_file=None, clone=None, sample=None,

def unpack(self):
"""Decode data section"""
eccodes.codes_set(self.codes_id, 'unpack', 1)
eccodes.codes_set(self.codes_id, "unpack", 1)

def pack(self):
"""Encode data section"""
eccodes.codes_set(self.codes_id, 'pack', 1)
eccodes.codes_set(self.codes_id, "pack", 1)

def keys(self, namespace=None):
#self.unpack()
#return super(self.__class__, self).keys(namespace)
# self.unpack()
# return super(self.__class__, self).keys(namespace)
iterator = eccodes.codes_bufr_keys_iterator_new(self.codes_id)
keys = []
while eccodes.codes_bufr_keys_iterator_next(iterator):
Expand All @@ -69,16 +67,16 @@ def keys(self, namespace=None):
eccodes.codes_bufr_keys_iterator_delete(iterator)
return keys

#@property
#def unpacked(self):
# @property
# def unpacked(self):
# return self._unpacked

#@unpacked.setter
#def unpacked(self, val):
# @unpacked.setter
# def unpacked(self, val):
# eccodes.codes_set(self.codes_id, "unpack", val)
# self._unpacked = val

#def __setitem__(self, key, value):
# def __setitem__(self, key, value):
# """Set item and pack BUFR."""
# if not self._unpacked:
# self.unpacked = True
Expand All @@ -89,9 +87,11 @@ def copy_data(self, destMsg):
"""Copy data values from this message to another message"""
return eccodes.codes_bufr_copy_data(self.codes_id, destMsg.codes_id)


class BufrFile(CodesFile):

__doc__ = "\n".join(CodesFile.__doc__.splitlines()[4:]).format(
prod_type="BUFR", classname="BufrFile", alias="bufr")
prod_type="BUFR", classname="BufrFile", alias="bufr"
)

MessageClass = BufrMessage
3 changes: 2 additions & 1 deletion eccodes/high_level/codesfile.py
Expand Up @@ -8,6 +8,7 @@
from .. import eccodes
import io


class CodesFile(io.FileIO):

"""
Expand Down Expand Up @@ -50,7 +51,7 @@ def __exit__(self, exception_type, exception_value, traceback):
while self.open_messages:
self.open_messages.pop().close()
eccodes.codes_close_file(self.file_handle)
#self.file_handle.close()
# self.file_handle.close()

def __len__(self):
"""Return total number of messages in file."""
Expand Down
37 changes: 24 additions & 13 deletions eccodes/high_level/codesmessage.py
Expand Up @@ -62,8 +62,14 @@ class CodesMessage(object):
#: ecCodes enum-like PRODUCT constant
product_kind = None

def __init__(self, codes_file=None, clone=None, sample=None,
headers_only=False, other_args_found=False):
def __init__(
self,
codes_file=None,
clone=None,
sample=None,
headers_only=False,
other_args_found=False,
):
"""
Open a message and inform the host file that it's been incremented.
Expand All @@ -75,16 +81,21 @@ def __init__(self, codes_file=None, clone=None, sample=None,
:param clone: A valid ``CodesMessage``
:param sample: A valid sample path to create ``CodesMessage`` from
"""
if not other_args_found and codes_file is None and clone is None and sample is None:
raise RuntimeError("CodesMessage initialization parameters not "
"present.")
if (
not other_args_found
and codes_file is None
and clone is None
and sample is None
):
raise RuntimeError("CodesMessage initialization parameters not " "present.")
#: Unique ID, for ecCodes interface
self.codes_id = None
#: File containing message
self.codes_file = None
if codes_file is not None:
self.codes_id = eccodes.codes_new_from_file(
codes_file.file_handle, self.product_kind, headers_only)
codes_file.file_handle, self.product_kind, headers_only
)
if self.codes_id is None:
raise IOError("CodesFile %s is exhausted" % codes_file.name)
self.codes_file = codes_file
Expand All @@ -93,8 +104,7 @@ def __init__(self, codes_file=None, clone=None, sample=None,
elif clone is not None:
self.codes_id = eccodes.codes_clone(clone.codes_id)
elif sample is not None:
self.codes_id = eccodes.codes_new_from_samples(
sample, self.product_kind)
self.codes_id = eccodes.codes_new_from_samples(sample, self.product_kind)

def write(self, outfile=None):
"""Write message to file."""
Expand All @@ -116,14 +126,15 @@ def __setitem__(self, key, value):
eccodes.codes_set(self.codes_id, key, value)
else:
if len(key) != len(value):
raise ValueError('Key array must have same size as value array')
eccodes.codes_set_key_vals(self.codes_id,",".join([str(key[i])+"="+str(value[i]) for i in range(len(key))]))

raise ValueError("Key array must have same size as value array")
eccodes.codes_set_key_vals(
self.codes_id,
",".join([str(key[i]) + "=" + str(value[i]) for i in range(len(key))]),
)

def keys(self, namespace=None):
"""Get available keys in message."""
iterator = eccodes.codes_keys_iterator_new(self.codes_id,
namespace=namespace)
iterator = eccodes.codes_keys_iterator_new(self.codes_id, namespace=namespace)
keys = []
while eccodes.codes_keys_iterator_next(iterator):
key = eccodes.codes_keys_iterator_get_name(iterator)
Expand Down

0 comments on commit e0c8218

Please sign in to comment.