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

Drop Python 3.9 #3612

Merged
merged 9 commits into from
Aug 28, 2024
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
2 changes: 0 additions & 2 deletions .github/workflows/docs-conda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ jobs:
fail-fast: false
matrix:
include:
- python-version: 3.9
os: Windows
- python-version: '3.10'
os: Windows
- python-version: 3.11
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.9, '3.10', 3.11]
python-version: ['3.10', 3.11]
check-links: [false]
include:
- python-version: 3.12
Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/tests-conda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,9 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.9, 3.12]
python-version: ['3.10', 3.12]
os: [macOS, Windows]
include:
- python-version: '3.10'
os: macOS
- python-version: 3.11
os: Windows

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/tests-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.9, '3.10', 3.11, 3.12]
python-version: ['3.10', 3.11, 3.12]
dep-versions: [Latest]
no-extras: ['']
include:
- python-version: 3.9
- python-version: '3.10'
dep-versions: Minimum
- python-version: 3.9
- python-version: '3.10'
dep-versions: Minimum
no-extras: 'No Extras'
- python-version: 3.12
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ on a future ``1.x`` version.
For additional MetPy examples not included in this repository, please see the [Unidata Python
Gallery](https://unidata.github.io/python-gallery/).

We support Python >= 3.9.
We support Python >= 3.10.

Need Help?
----------
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ MetPy
=====

MetPy is a collection of tools in Python for reading, visualizing, and performing calculations
with weather data. MetPy supports Python >= 3.9 and is freely available under a permissive
with weather data. MetPy supports Python >= 3.10 and is freely available under a permissive
`open source license <https://github.com/Unidata/MetPy/blob/main/LICENSE>`_.

If you're new to MetPy, check out our :doc:`Getting Started <userguide/startingguide>` guide.
Expand Down
2 changes: 1 addition & 1 deletion docs/userguide/installguide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Requirements
------------
In general, MetPy tries to support minor versions of dependencies released within the last two
years. For Python itself, that generally means supporting the last two minor releases; MetPy
currently supports Python >= 3.9.
currently supports Python >= 3.10.

.. literalinclude:: ../../pyproject.toml
:start-at: matplotlib
Expand Down
3 changes: 2 additions & 1 deletion examples/formats/NEXRAD_Level_2_File.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@
fig = plt.figure(figsize=(15, 8))
add_metpy_logo(fig, 190, 85, size='large')

for var_data, var_range, ax_rect in zip((ref, rho), (ref_range, rho_range), spec):
for var_data, var_range, ax_rect in zip((ref, rho), (ref_range, rho_range), spec,
strict=False):
# Turn into an array, then mask
data = np.ma.array(var_data)
data[np.isnan(data)] = np.ma.masked
Expand Down
2 changes: 1 addition & 1 deletion examples/formats/NEXRAD_Level_3_File.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
ctables = (('NWSStormClearReflectivity', -20, 0.5), # dBZ
('NWS8bitVel', -100, 1.0)) # m/s

for v, ctable, ax_rect in zip(('N0Q', 'N0U'), ctables, spec):
for v, ctable, ax_rect in zip(('N0Q', 'N0U'), ctables, spec, strict=False):
# Open the file
name = get_test_data(f'nids/KOUN_SDUS54_{v}TLX_201305202016', as_file_obj=False)
f = Level3File(name)
Expand Down
10 changes: 5 additions & 5 deletions examples/gridding/Inverse_Distance_Verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ def draw_circle(ax, x, y, r, m, label):
#
# The variable ``indices`` represents the index of each matched coordinate within the
# cKDTree's ``data`` list.
grid_points = np.array(list(zip(sim_gridx, sim_gridy)))
grid_points = np.array(list(zip(sim_gridx, sim_gridy, strict=False)))

radius = 40
obs_tree = cKDTree(list(zip(xp, yp)))
obs_tree = cKDTree(list(zip(xp, yp, strict=False)))
indices = obs_tree.query_ball_point(grid_points, r=radius)

###########################################
Expand All @@ -83,7 +83,7 @@ def draw_circle(ax, x, y, r, m, label):
barnes_dist = dist_2(sim_gridx[1], sim_gridy[1], x2, y2)
barnes_obs = zp[indices[1]]

kappa = calc_kappa(average_spacing(list(zip(xp, yp))))
kappa = calc_kappa(average_spacing(list(zip(xp, yp, strict=False))))

barnes_val = barnes_point(barnes_dist, barnes_obs, kappa)

Expand Down Expand Up @@ -121,7 +121,7 @@ def draw_circle(ax, x, y, r, m, label):
mx, my = obs_tree.data[indices[0]].T
mz = zp[indices[0]]

for x, y, z in zip(mx, my, mz):
for x, y, z in zip(mx, my, mz, strict=False):
d = np.sqrt((sim_gridx[0] - x)**2 + (y - sim_gridy[0])**2)
ax.plot([sim_gridx[0], x], [sim_gridy[0], y], '--')

Expand Down Expand Up @@ -160,7 +160,7 @@ def draw_circle(ax, x, y, r, m, label):
mx, my = obs_tree.data[indices[1]].T
mz = zp[indices[1]]

for x, y, z in zip(mx, my, mz):
for x, y, z in zip(mx, my, mz, strict=False):
d = np.sqrt((sim_gridx[1] - x)**2 + (y - sim_gridy[1])**2)
ax.plot([sim_gridx[1], x], [sim_gridy[1], y], '--')

Expand Down
7 changes: 4 additions & 3 deletions examples/gridding/Natural_Neighbor_Verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@
ax.set_title('Triangulation of observations and test grid cell '
'natural neighbor interpolation values')

members, circumcenters = geometry.find_natural_neighbors(tri, list(zip(sim_gridx, sim_gridy)))
members, circumcenters = geometry.find_natural_neighbors(tri, list(zip(sim_gridx, sim_gridy,
strict=False)))

val = natural_neighbor_point(xp, yp, zp, (sim_gridx[0], sim_gridy[0]), tri, members[0],
circumcenters)
Expand Down Expand Up @@ -164,7 +165,7 @@ def draw_circle(ax, x, y, r, m, label):
# spatial data structure that we use here simply to show areal ratios.
# Notice that the two natural neighbor triangle circumcenters are also vertices
# in the Voronoi plot (green dots), and the observations are in the polygons (blue dots).
vort = Voronoi(list(zip(xp, yp)))
vort = Voronoi(list(zip(xp, yp, strict=False)))

fig, ax = plt.subplots(1, 1, figsize=(15, 10))
ax.ishold = lambda: True # Work-around for Matplotlib 3.0.0 incompatibility
Expand All @@ -175,7 +176,7 @@ def draw_circle(ax, x, y, r, m, label):
x_0 = xp[nn_ind]
y_0 = yp[nn_ind]

for x, y, z in zip(x_0, y_0, z_0):
for x, y, z in zip(x_0, y_0, z_0, strict=False):
ax.annotate(f'{x}, {y}: {z:.3f} F', xy=(x, y))

ax.plot(sim_gridx[0], sim_gridy[0], 'k+', markersize=10)
Expand Down
2 changes: 1 addition & 1 deletion examples/plots/Plotting_Surface_Analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def plot_bulletin(ax, data):
# Handle H/L points using MetPy's StationPlot class
for field in ('HIGH', 'LOW'):
rows = data[data.feature == field]
x, y = zip(*((pt.x, pt.y) for pt in rows.geometry))
x, y = zip(*((pt.x, pt.y) for pt in rows.geometry), strict=False)
sp = StationPlot(ax, x, y, transform=ccrs.PlateCarree(), clip_on=True)
sp.plot_text('C', [field[0]] * len(x), **complete_style[field])
sp.plot_parameter('S', rows.strength, **complete_style[field])
Expand Down
2 changes: 1 addition & 1 deletion examples/plots/US_Counties.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@
ax2 = fig.add_subplot(1, 3, 2, projection=proj)
ax3 = fig.add_subplot(1, 3, 3, projection=proj)

for scale, axis in zip(['20m', '5m', '500k'], [ax1, ax2, ax3]):
for scale, axis in zip(['20m', '5m', '500k'], [ax1, ax2, ax3], strict=False):
axis.set_extent([270.25, 270.9, 38.15, 38.75], ccrs.Geodetic())
axis.add_feature(USCOUNTIES.with_scale(scale))
13 changes: 6 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ classifiers = [
"Development Status :: 5 - Production/Stable",
"Framework :: Matplotlib",
"Programming Language :: Python",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand All @@ -24,17 +23,17 @@ classifiers = [
"Operating System :: OS Independent",
"License :: OSI Approved :: BSD License"
]
requires-python = ">=3.9"
requires-python = ">=3.10"
dependencies = [
"matplotlib>=3.5.0",
"numpy>=1.20.0",
"numpy>=1.22.0",
"pandas>=1.4.0",
"pint>=0.17",
"pooch>=1.2.0",
"pyproj>=3.0.0",
"pyproj>=3.3.0",
"scipy>=1.8.0",
"traitlets>=5.0.5",
"xarray>=0.21.0"
"traitlets>=5.1.0",
"xarray>=2022.6.0"
]

[project.entry-points."xarray.backends"]
Expand All @@ -57,7 +56,7 @@ examples = [
test = [
"netCDF4",
"packaging>=21.0",
"pytest>=6.2",
"pytest>=7.0",
"pytest-mpl"
]
extras = [
Expand Down
2 changes: 1 addition & 1 deletion src/metpy/calc/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1130,7 +1130,7 @@ def zoom_xarray(input_field, zoom, output=None, order=3, mode='constant', cval=0
if not np.iterable(zoom):
zoom = tuple(zoom for _ in input_field.dims)
zoomed_dim_coords = {}
for dim_name, dim_zoom in zip(input_field.dims, zoom):
for dim_name, dim_zoom in zip(input_field.dims, zoom, strict=False):
if dim_name in input_field.coords:
zoomed_dim_coords[dim_name] = scipy_zoom(
input_field[dim_name].data, dim_zoom, order=order, mode=mode, cval=cval,
Expand Down
2 changes: 1 addition & 1 deletion src/metpy/calc/kinematics.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ def advection(

return -sum(
wind * gradient
for wind, gradient in zip(wind_vector.values(), gradient_vector)
for wind, gradient in zip(wind_vector.values(), gradient_vector, strict=False)
)


Expand Down
2 changes: 1 addition & 1 deletion src/metpy/calc/thermo.py
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,7 @@ def _wide_option(intersect_type, p_list, t_list, pressure, parcel_temperature_pr
lfc_p_list, _ = find_intersections(pressure, parcel_temperature_profile,
temperature, direction='increasing',
log_x=True)
diff = [lfc_p.m - el_p.m for lfc_p, el_p in zip(lfc_p_list, el_p_list)]
diff = [lfc_p.m - el_p.m for lfc_p, el_p in zip(lfc_p_list, el_p_list, strict=False)]
return (p_list[np.where(diff == np.max(diff))][0],
t_list[np.where(diff == np.max(diff))][0])

Expand Down
6 changes: 3 additions & 3 deletions src/metpy/interpolate/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def natural_neighbor_to_grid(xp, yp, variable, grid_x, grid_y):

"""
# Handle grid-to-points conversion, and use function from `interpolation`
points_obs = list(zip(xp, yp))
points_obs = list(zip(xp, yp, strict=False))
points_grid = generate_grid_coords(grid_x, grid_y)
img = natural_neighbor_to_points(points_obs, variable, points_grid)
return img.reshape(grid_x.shape)
Expand Down Expand Up @@ -214,7 +214,7 @@ def inverse_distance_to_grid(xp, yp, variable, grid_x, grid_y, r, gamma=None, ka

"""
# Handle grid-to-points conversion, and use function from `interpolation`
points_obs = list(zip(xp, yp))
points_obs = list(zip(xp, yp, strict=False))
points_grid = generate_grid_coords(grid_x, grid_y)
img = inverse_distance_to_points(points_obs, variable, points_grid, r, gamma=gamma,
kappa=kappa, min_neighbors=min_neighbors, kind=kind)
Expand Down Expand Up @@ -296,7 +296,7 @@ def interpolate_to_grid(x, y, z, interp_type='linear', hres=50000,
grid_x, grid_y = generate_grid(hres, boundary_coords)

# Handle grid-to-points conversion, and use function from `interpolation`
points_obs = np.array(list(zip(x, y)))
points_obs = np.array(list(zip(x, y, strict=False)))
points_grid = generate_grid_coords(grid_x, grid_y)
img = interpolate_to_points(points_obs, z, points_grid, interp_type=interp_type,
minimum_neighbors=minimum_neighbors, gamma=gamma,
Expand Down
6 changes: 3 additions & 3 deletions src/metpy/interpolate/points.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def cressman_point(sq_dist, values, radius):
weights = tools.cressman_weights(sq_dist, radius)
total_weights = np.sum(weights)

return sum(v * (w / total_weights) for (w, v) in zip(weights, values))
return sum(v * (w / total_weights) for (w, v) in zip(weights, values, strict=False))


def barnes_point(sq_dist, values, kappa, gamma=None):
Expand Down Expand Up @@ -82,7 +82,7 @@ def barnes_point(sq_dist, values, kappa, gamma=None):
weights = tools.barnes_weights(sq_dist, kappa, gamma)
total_weights = np.sum(weights)

return sum(v * (w / total_weights) for (w, v) in zip(weights, values))
return sum(v * (w / total_weights) for (w, v) in zip(weights, values, strict=False))


def natural_neighbor_point(xp, yp, variable, grid_loc, tri, neighbors, circumcenters):
Expand Down Expand Up @@ -271,7 +271,7 @@ def inverse_distance_to_points(points, values, xi, r, gamma=None, kappa=None, mi

img = np.asarray([interp_func(geometry.dist_2(*grid, *obs_tree.data[matches].T),
values[matches]) if len(matches) >= min_neighbors else np.nan
for matches, grid in zip(indices, xi)])
for matches, grid in zip(indices, xi, strict=False)])

if org_units:
img = units.Quantity(img, org_units)
Expand Down
2 changes: 1 addition & 1 deletion src/metpy/interpolate/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def remove_repeat_coordinates(x, y, z):
coords = []
variable = []

for (x_, y_, t_) in zip(x, y, z):
for (x_, y_, t_) in zip(x, y, z, strict=False):
if (x_, y_) not in coords:
coords.append((x_, y_))
variable.append(t_)
Expand Down
8 changes: 4 additions & 4 deletions src/metpy/io/_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def __init__(self, info, prefmt='', tuple_name=None):
"""Initialize the NamedStruct."""
if tuple_name is None:
tuple_name = 'NamedStruct'
names, fmts = zip(*info)
names, fmts = zip(*info, strict=False)
self.converters = {}
conv_off = 0
for ind, i in enumerate(info):
Expand Down Expand Up @@ -118,7 +118,7 @@ class DictStruct:

def __init__(self, info, prefmt=''):
"""Initialize the DictStruct."""
names, formats = zip(*info)
names, formats = zip(*info, strict=False)

# Remove empty names
self._names = [n for n in names if n]
Expand All @@ -131,7 +131,7 @@ def size(self):
return self._struct.size

def _create(self, items):
return dict(zip(self._names, items))
return dict(zip(self._names, items, strict=False))

def unpack(self, s):
"""Parse bytes and return a dict."""
Expand All @@ -151,7 +151,7 @@ def __init__(self, *args, **kwargs):
self.val_map = dict(enumerate(args))

# Invert the kwargs dict so that we can map from value to name
self.val_map.update(zip(kwargs.values(), kwargs.keys()))
self.val_map.update(zip(kwargs.values(), kwargs.keys(), strict=False))

def __call__(self, val):
"""Map an integer to the string representation."""
Expand Down
9 changes: 5 additions & 4 deletions src/metpy/io/gempak.py
Original file line number Diff line number Diff line change
Expand Up @@ -629,8 +629,9 @@ def __init__(self, file):
fkey_prod = product(['header_name', 'header_length', 'header_type'],
range(1, self.prod_desc.file_headers + 1))
fkey_names = ['{}{}'.format(*x) for x in fkey_prod]
fkey_info = list(zip(fkey_names, np.repeat(('4s', 'i', 'i'),
self.prod_desc.file_headers)))
fkey_info = list(zip(fkey_names,
np.repeat(('4s', 'i', 'i'), self.prod_desc.file_headers),
strict=False))
self.file_keys_format = NamedStruct(fkey_info, self.prefmt, 'FileKeys')

self._buffer.jump_to(self._start, _word_to_position(self.prod_desc.file_keys_ptr))
Expand Down Expand Up @@ -790,7 +791,7 @@ def _convert_ftime(ftime):
@staticmethod
def _convert_level(level):
"""Convert levels."""
if isinstance(level, (int, float)) and level >= 0:
if isinstance(level, int | float) and level >= 0:
return level
else:
return None
Expand Down Expand Up @@ -1897,7 +1898,7 @@ def _merge_sounding(self, parts):
if num_man_levels >= 1:
for mp, mt, mz in zip(parts['TTAA']['PRES'],
parts['TTAA']['TEMP'],
parts['TTAA']['HGHT']):
parts['TTAA']['HGHT'], strict=False):
if self.prod_desc.missing_float not in [
mp,
mt,
Expand Down
2 changes: 1 addition & 1 deletion src/metpy/io/gini.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def _scaled_int(s):

def _name_lookup(names):
r"""Create an io helper to convert an integer to a named value."""
mapper = dict(zip(range(len(names)), names))
mapper = dict(zip(range(len(names)), names, strict=False))

def lookup(val):
return mapper.get(val, 'UnknownValue')
Expand Down
Loading