Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dependencies update #4130

Merged
merged 8 commits into from
May 13, 2021
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
12 changes: 7 additions & 5 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ test_minimal_task:
PY_VER: 3.6
env:
PY_VER: 3.7
env:
PY_VER: 3.8
name: "${CIRRUS_OS}: py${PY_VER} tests (minimal)"
container:
image: gcc:latest
Expand All @@ -143,6 +145,8 @@ test_full_task:
PY_VER: 3.6
env:
PY_VER: 3.7
env:
PY_VER: 3.8
name: "${CIRRUS_OS}: py${PY_VER} tests (full)"
container:
image: gcc:latest
Expand Down Expand Up @@ -172,9 +176,7 @@ gallery_task:
<< : *CREDITS_TEMPLATE
matrix:
env:
PY_VER: 3.6
env:
PY_VER: 3.7
PY_VER: 3.8
name: "${CIRRUS_OS}: py${PY_VER} doc tests (gallery)"
container:
image: gcc:latest
Expand Down Expand Up @@ -204,7 +206,7 @@ doctest_task:
<< : *CREDITS_TEMPLATE
matrix:
env:
PY_VER: 3.7
PY_VER: 3.8
name: "${CIRRUS_OS}: py${PY_VER} doc tests"
container:
image: gcc:latest
Expand Down Expand Up @@ -240,7 +242,7 @@ linkcheck_task:
<< : *CREDITS_TEMPLATE
matrix:
env:
PY_VER: 3.7
PY_VER: 3.8
name: "${CIRRUS_OS}: py${PY_VER} doc link check"
container:
image: gcc:latest
Expand Down
6 changes: 3 additions & 3 deletions docs/iris/gallery_code/general/plot_anomaly_log_colouring.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ def main():
# Create a 'logarithmic' data normalization.
anom_norm = mcols.SymLogNorm(
linthresh=minimum_log_level,
linscale=0,
linscale=0.01,
vmin=-maximum_scale_level,
vmax=maximum_scale_level,
)
# Setting "linthresh=minimum_log_level" makes its non-logarithmic
# data range equal to our 'zero band'.
# Setting "linscale=0" maps the whole zero band to the middle colour value
# (i.e. 0.5), which is the neutral point of a "diverging" style colormap.
# Setting "linscale=0.01" maps the whole zero band to the middle colour value
# (i.e., 0.5), which is the neutral point of a "diverging" style colormap.

# Create an Axes, specifying the map projection.
plt.axes(projection=ccrs.LambertConformal())
Expand Down
2 changes: 1 addition & 1 deletion docs/iris/src/developers_guide/gitwash/git_links.inc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@
.. _git config: http://schacon.github.com/git/git-config.html

.. _linux git workflow: http://www.mail-archive.com/[email protected]/msg39091.html
.. _deleting master on github: http://matthew-brett.github.com/pydagogue/gh_delete_master.html
.. _deleting master on github: https://matthew-brett.github.io/pydagogue/gh_delete_master.html

.. |emdash| unicode:: U+02014
7 changes: 3 additions & 4 deletions docs/iris/src/further_topics/metadata.rst
Original file line number Diff line number Diff line change
Expand Up @@ -258,12 +258,12 @@ create a **new** instance directly from the metadata class itself,
>>> DimCoordMetadata._make(values)
DimCoordMetadata(standard_name=1, long_name=2, var_name=3, units=4, attributes=5, coord_system=6, climatological=7, circular=8)

It is also possible to easily convert ``metadata`` to an `OrderedDict`_
It is also possible to easily convert ``metadata`` to an `dict`_
using the `namedtuple._asdict`_ method. This can be particularly handy when a
standard Python built-in container is required to represent your ``metadata``,

>>> metadata._asdict()
OrderedDict([('standard_name', 'longitude'), ('long_name', None), ('var_name', 'longitude'), ('units', Unit('degrees')), ('attributes', {'grinning face': '🙃'}), ('coord_system', GeogCS(6371229.0)), ('climatological', False), ('circular', False)])
{'standard_name': 'longitude', 'long_name': None, 'var_name': 'longitude', 'units': Unit('degrees'), 'attributes': {'grinning face': '🙃'}, 'coord_system': GeogCS(6371229.0), 'climatological': False, 'circular': False}

Using the `namedtuple._replace`_ method allows you to create a new metadata
class instance, but replacing specified members with **new** associated values,
Expand Down Expand Up @@ -943,7 +943,7 @@ such as a `dict`_,

>>> mapping = latitude.metadata._asdict()
>>> mapping
OrderedDict([('standard_name', 'latitude'), ('long_name', None), ('var_name', 'latitude'), ('units', Unit('degrees')), ('attributes', {}), ('coord_system', GeogCS(6371229.0)), ('climatological', False), ('circular', False)])
{'standard_name': 'latitude', 'long_name': None, 'var_name': 'latitude', 'units': Unit('degrees'), 'attributes': {}, 'coord_system': GeogCS(6371229.0), 'climatological': False, 'circular': False}
>>> longitude.metadata = mapping
>>> longitude.metadata
DimCoordMetadata(standard_name='latitude', long_name=None, var_name='latitude', units=Unit('degrees'), attributes={}, coord_system=GeogCS(6371229.0), climatological=False, circular=False)
Expand Down Expand Up @@ -1000,7 +1000,6 @@ values. All other metadata members will be left unaltered.
.. _NetCDF: https://www.unidata.ucar.edu/software/netcdf/
.. _NetCDF CF Metadata Conventions: https://cfconventions.org/
.. _NumPy: https://github.com/numpy/numpy
.. _OrderedDict: https://docs.python.org/3/library/collections.html#collections.OrderedDict
.. _Parametric Vertical Coordinate: https://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#parametric-vertical-coordinate
.. _rich comparison: https://www.python.org/dev/peps/pep-0207/
.. _SciTools/iris: https://github.com/SciTools/iris
Expand Down
4 changes: 2 additions & 2 deletions docs/iris/src/installing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ any WSL_ distributions.

.. _WSL: https://docs.microsoft.com/en-us/windows/wsl/install-win10

.. note:: Iris currently supports and is tested against **Python 3.6** and
**Python 3.7**.
.. note:: Iris is currently supported and tested against Python ``3.6``,
``3.7``, and ``3.8``.


.. _installing_using_conda:
Expand Down
77 changes: 70 additions & 7 deletions lib/iris/coords.py
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,21 @@ def shape(self):
return self._values_dm.shape

def xml_element(self, doc):
"""Return a DOM element describing this metadata."""
"""
Create the :class:`xml.dom.minidom.Element` that describes this
:class:`_DimensionalMetadata`.

Args:

* doc:
The parent :class:`xml.dom.minidom.Document`.

Returns:
The :class:`xml.dom.minidom.Element` that will describe this
:class:`_DimensionalMetadata`, and the dictionary of attributes
that require to be added to this element.

"""
# Create the XML element as the camelCaseEquivalent of the
# class name.
element_name = type(self).__name__
Expand Down Expand Up @@ -882,6 +896,20 @@ def cube_dims(self, cube):
return cube.cell_measure_dims(self)

def xml_element(self, doc):
"""
Create the :class:`xml.dom.minidom.Element` that describes this
:class:`CellMeasure`.

Args:

* doc:
The parent :class:`xml.dom.minidom.Document`.

Returns:
The :class:`xml.dom.minidom.Element` that describes this
:class:`CellMeasure`.

"""
# Create the XML element as the camelCaseEquivalent of the
# class name
element = super().xml_element(doc=doc)
Expand Down Expand Up @@ -2229,14 +2257,26 @@ def nearest_neighbour_index(self, point):
return result_index

def xml_element(self, doc):
"""Return a DOM element describing this Coord."""
"""
Create the :class:`xml.dom.minidom.Element` that describes this
:class:`Coord`.

Args:

* doc:
The parent :class:`xml.dom.minidom.Document`.

Returns:
The :class:`xml.dom.minidom.Element` that will describe this
:class:`DimCoord`, and the dictionary of attributes that require
to be added to this element.

"""
# Create the XML element as the camelCaseEquivalent of the
# class name
element = super().xml_element(doc=doc)

element.setAttribute("points", self._xml_array_repr(self.points))

# Add bounds handling
# Add bounds, points are handled by the parent class.
if self.has_bounds():
element.setAttribute("bounds", self._xml_array_repr(self.bounds))

Expand Down Expand Up @@ -2613,7 +2653,20 @@ def is_monotonic(self):
return True

def xml_element(self, doc):
"""Return DOM element describing this :class:`iris.coords.DimCoord`."""
"""
Create the :class:`xml.dom.minidom.Element` that describes this
:class:`DimCoord`.

Args:

* doc:
The parent :class:`xml.dom.minidom.Document`.

Returns:
The :class:`xml.dom.minidom.Element` that describes this
:class:`DimCoord`.

"""
element = super().xml_element(doc)
if self.circular:
element.setAttribute("circular", str(self.circular))
Expand Down Expand Up @@ -2754,7 +2807,17 @@ def __add__(self, other):

def xml_element(self, doc):
"""
Return a dom element describing itself
Create the :class:`xml.dom.minidom.Element` that describes this
:class:`CellMethod`.

Args:

* doc:
The parent :class:`xml.dom.minidom.Document`.

Returns:
The :class:`xml.dom.minidom.Element` that describes this
:class:`CellMethod`.

"""
cellMethod_xml_element = doc.createElement("cellMethod")
Expand Down
56 changes: 56 additions & 0 deletions lib/iris/cube.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ def __getslice__(self, start, stop):

def xml(self, checksum=False, order=True, byteorder=True):
"""Return a string of the XML that this list of cubes represents."""

doc = Document()
cubes_xml_element = doc.createElement("cubes")
cubes_xml_element.setAttribute("xmlns", XML_NAMESPACE_URI)
Expand All @@ -239,6 +240,7 @@ def xml(self, checksum=False, order=True, byteorder=True):
doc.appendChild(cubes_xml_element)

# return our newly created XML string
doc = Cube._sort_xml_attrs(doc)
return doc.toprettyxml(indent=" ")

def extract(self, constraints):
Expand Down Expand Up @@ -755,6 +757,59 @@ class Cube(CFVariableMixin):
#: is similar to Fortran or Matlab, but different than numpy.
__orthogonal_indexing__ = True

@classmethod
def _sort_xml_attrs(cls, doc):
"""
Takes an xml document and returns a copy with all element
attributes sorted in alphabetical order.

This is a private utility method required by iris to maintain
legacy xml behaviour beyond python 3.7.

Args:

* doc:
The :class:`xml.dom.minidom.Document`.

Returns:
The :class:`xml.dom.minidom.Document` with sorted element
attributes.

"""
from xml.dom.minidom import Document

def _walk_nodes(node):
"""Note: _walk_nodes is called recursively on child elements."""

# we don't want to copy the children here, so take a shallow copy
new_node = node.cloneNode(deep=False)

# Versions of python <3.8 order attributes in alphabetical order.
# Python >=3.8 order attributes in insert order. For consistent behaviour
# across both, we'll go with alphabetical order always.
# Remove all the attribute nodes, then add back in alphabetical order.
attrs = [
new_node.getAttributeNode(attr_name).cloneNode(deep=True)
for attr_name in sorted(node.attributes.keys())
]
for attr in attrs:
new_node.removeAttributeNode(attr)
for attr in attrs:
new_node.setAttributeNode(attr)

if node.childNodes:
children = [_walk_nodes(x) for x in node.childNodes]
for c in children:
new_node.appendChild(c)

return new_node

nodes = _walk_nodes(doc.documentElement)
new_doc = Document()
new_doc.appendChild(nodes)

return new_doc

def __init__(
self,
data,
Expand Down Expand Up @@ -3399,6 +3454,7 @@ def xml(self, checksum=False, order=True, byteorder=True):
doc.appendChild(cube_xml_element)

# Print our newly created XML
doc = self._sort_xml_attrs(doc)
return doc.toprettyxml(indent=" ")

def _xml_element(self, doc, checksum=False, order=True, byteorder=True):
Expand Down
12 changes: 12 additions & 0 deletions lib/iris/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,18 @@ def contourf(cube, *args, **kwargs):
# any boundary shift.
zorder = result.collections[0].zorder - 0.1
axes = kwargs.get("axes", None)

# Workaround for cartopy#1780. We do not want contour to shrink
# extent.
if axes is None:
_axes = plt.gca()
else:
_axes = axes

# Subsequent calls to dataLim.update_from_data_xy should not ignore
# current extent.
_axes.dataLim.ignore(False)

contour(
cube,
levels=levels,
Expand Down
4 changes: 4 additions & 0 deletions lib/iris/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,10 @@ def assertXMLElement(self, obj, reference_filename):
"""
doc = xml.dom.minidom.Document()
doc.appendChild(obj.xml_element(doc))
# sort the attributes on xml elements before testing against known good state.
# this is to be compatible with stored test output where xml attrs are stored in alphabetical order,
# (which was default behaviour in python <3.8, but changed to insert order in >3.8)
doc = iris.cube.Cube._sort_xml_attrs(doc)
pretty_xml = doc.toprettyxml(indent=" ")
reference_path = self.get_result_path(reference_filename)
self._check_same(
Expand Down
2 changes: 1 addition & 1 deletion lib/iris/tests/results/analysis/sqrt.cml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@
</coord>
</coords>
<cellMethods/>
<data checksum="0x09ef96ca" dtype="float64" shape="(73, 96)"/>
<data dtype="float64" shape="(73, 96)" state="loaded"/>
</cube>
</cubes>
Loading