Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ tox
tox-pyenv
wheel
zest.releaser
black
1 change: 1 addition & 0 deletions ci/requirements-py36-qc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ dependencies:
- pytest-pep8
- python=3.6
- typing
- black
1 change: 1 addition & 0 deletions ci/requirements-py36.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ dependencies:
- pytest-cov
- python=3.6
- typing
- black
1 change: 1 addition & 0 deletions ci/requirements-py37.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ dependencies:
- pytest-flakes
- python=3.7
- typing
- black
22 changes: 11 additions & 11 deletions docs/conf.py
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading