Skip to content

Commit 6e61d48

Browse files
author
Joe Hamman
committed
Merge pull request #20 from jhamman/feature/pycompat
add pycompat module and included some minor python3 fixes
2 parents 2bf5167 + 55041c1 commit 6e61d48

File tree

10 files changed

+114
-48
lines changed

10 files changed

+114
-48
lines changed

tests/test_pycompat.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from tonic.pycompat import pyrange, pyzip, iteritems
2+
3+
4+
def test_pyrange():
5+
x = pyrange(5)
6+
assert list(x) == [0, 1, 2, 3, 4]
7+
8+
9+
def test_pyzip():
10+
a = [1, 2, 3]
11+
b = ['a', 'b', 'c']
12+
13+
z = pyzip(a, b)
14+
assert hasattr(z, '__iter__')
15+
lz = list(pyzip(a, b))
16+
assert lz[0] == (1, 'a')
17+
assert len(lz) == len(a) # == len(b)
18+
19+
20+
def test_iteritems():
21+
d = {'a': 0, 'b': 1, 'c': 2}
22+
for k, v in iteritems(d):
23+
assert type(k) == str
24+
assert type(v) == int

tests/test_vic2netcdf.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#!/usr/local/env python
21
"""Set to run with pytest
32
43
Usage: py.test

tonic/io.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
11
#!/usr/bin/env python
22
"""Input/Output functions"""
33
from netCDF4 import Dataset
4-
try:
5-
from cyordereddict import OrderedDict
6-
except:
7-
from collections import OrderedDict
8-
try:
9-
from configparser import SafeConfigParser
10-
except:
11-
from ConfigParser import SafeConfigParser
124
import configobj
5+
from .pycompat import OrderedDict, SafeConfigParser
136

147

158
# -------------------------------------------------------------------- #

tonic/models/vic/compare_soil_params.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from matplotlib import rcParams
1515
from tonic.io import read_netcdf
1616
from tonic.plot_utils import sub_plot_pcolor, cmap_discretize
17+
from tonic.pycompat import pyrange
1718

1819
description = 'Create plots comparing two sets of VIC soil parameters'
1920
help = 'Create plots comparing two sets of VIC soil parameters'
@@ -275,7 +276,7 @@ def my_plot9(lons, lats, d1, d2, units=None,
275276
f, axarr = plt.subplots(3, 3, figsize=(13.5, 9), dpi=150)
276277
f.tight_layout()
277278

278-
for layer in xrange(3):
279+
for layer in pyrange(3):
279280
plt.sca(axarr[layer, 0])
280281
sub_plot_pcolor(lons, lats, np.ma.masked_where(mask, d1[layer]),
281282
vmin=vmin, vmax=vmax, units=units,

tonic/models/vic/grid_params.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
import socket
1616
from getpass import getuser
1717
from collections import OrderedDict
18+
from warnings import warn
1819
from tonic.io import read_netcdf
20+
from tonic.pycompat import pyrange, pyzip
21+
1922

2023
# -------------------------------------------------------------------- #
2124
description = 'Converter for VIC ASCII style parameters to gridded netCDF'
@@ -123,12 +126,11 @@ def __init__(self, nlayers=3, snow_bands=5):
123126
('lib_albedo', np.arange(16, 28)),
124127
('lib_veg_rough', np.arange(28, 40)),
125128
('lib_displacement', np.arange(40, 52)),
126-
('lib_wind_h', np.array(52)),
127-
('lib_RGL', np.array(53)),
128-
('lib_rad_atten', np.array(54)),
129-
('lib_wind_atten', np.array(55)),
130-
('lib_trunk_ratio', np.array(56)),
131-
('lib_snow_albedo', np.array(57))])
129+
('lib_wind_h', np.array([52])),
130+
('lib_RGL', np.array([53])),
131+
('lib_rad_atten', np.array([54])),
132+
('lib_wind_atten', np.array([55])),
133+
('lib_trunk_ratio', np.array([56]))])
132134
# -------------------------------------------------------------------- #
133135

134136

@@ -507,14 +509,14 @@ def calc_grid(lats, lons, decimals=4):
507509

508510
# check that counts and steps make sense
509511
if lon_step != lat_step:
510-
print('WARNING: lon_step ({0}) and lat_step ({1}) do not '
511-
'match'.format(lon_step, lat_step))
512+
warn('lon_step ({0}) and lat_step ({1}) do not '
513+
'match'.format(lon_step, lat_step))
512514
if lat_count / len(ulats) < 0.95:
513-
print('WARNING: lat_count of mode is less than 95% ({0}%) of'
514-
' len(lats)'.format(lat_count / len(ulats)))
515+
warn('lat_count of mode is less than 95% ({0}%) of'
516+
' len(lats)'.format(lat_count / len(ulats)))
515517
if lon_count / len(ulons) < 0.95:
516-
print('WARNING: lon_count of mode is less than 95% ({0}%) of'
517-
' len(lons)'.format(lon_count / len(ulons)))
518+
warn('lon_count of mode is less than 95% ({0}%) of'
519+
' len(lons)'.format(lon_count / len(ulons)))
518520

519521
if lats.min() < -55 and lats.max() > 70:
520522
# assume global grid
@@ -644,7 +646,7 @@ def grid_params(soil_dict, target_grid, snow_dict, veg_dict, veglib_dict,
644646
steps = mydict[var].shape[1]
645647
out_dict[var] = np.ma.zeros((steps, ysize, xsize),
646648
dtype=dtype)
647-
for i in xrange(steps):
649+
for i in pyrange(steps):
648650
out_dict[var][i, yi, xi] = mydict[var][:, i]
649651
out_dict[var][:, ymask, xmask] = fill_val
650652

@@ -653,10 +655,10 @@ def grid_params(soil_dict, target_grid, snow_dict, veg_dict, veglib_dict,
653655
k = mydict[var].shape[2]
654656
out_dict[var] = np.ma.zeros((j, k, ysize, xsize),
655657
dtype=dtype)
656-
for jj in xrange(j):
657-
for kk in xrange(k):
658+
for jj in pyrange(j):
659+
for kk in pyrange(k):
658660
out_dict[var][jj, kk, yi, xi] = mydict[var][:, jj, kk]
659-
for y, x in zip(ymask, xmask):
661+
for y, x in pyzip(ymask, xmask):
660662
out_dict[var][:, :, y, x] = fill_val
661663

662664
out_dict[var] = np.ma.masked_values(out_dict[var], fill_val)
@@ -710,7 +712,7 @@ def grid_params(soil_dict, target_grid, snow_dict, veg_dict, veglib_dict,
710712
new = np.zeros(shape) + FILLVALUE_F
711713
new[:-1, :, yi, xi] = veglib_dict[lib_var][:, :, np.newaxis]
712714
new[-1, :, yi, xi] = 0
713-
for y, x in zip(ymask, xmask):
715+
for y, x in pyzip(ymask, xmask):
714716
new[:, :, y, x] = fill_val
715717
out_dicts['veg_dict'][var] = np.ma.masked_values(new, FILLVALUE_F)
716718

@@ -1021,7 +1023,6 @@ def veg(veg_file, soil_dict, max_roots=3, veg_classes=11,
10211023

10221024
row = 0
10231025
cell = 0
1024-
10251026
while row < len(lines):
10261027
line = lines[row].strip('\n').split(' ')
10271028
gridcel[cell], nveg[cell] = np.array(line).astype(int)
@@ -1078,7 +1079,7 @@ def veg(veg_file, soil_dict, max_roots=3, veg_classes=11,
10781079

10791080

10801081
# -------------------------------------------------------------------- #
1081-
def veg_class(veg_file, maxcols=58, skiprows=3, c=Cols()):
1082+
def veg_class(veg_file, maxcols=57, skiprows=3, c=Cols()):
10821083
"""
10831084
Load the entire vegetation library file into a dictionary of numpy arrays.
10841085
Also reorders data to match gridcell order of soil file.
@@ -1087,7 +1088,6 @@ def veg_class(veg_file, maxcols=58, skiprows=3, c=Cols()):
10871088
print('reading {0}'.format(veg_file))
10881089

10891090
usecols = np.arange(maxcols)
1090-
print(usecols, maxcols, skiprows)
10911091

10921092
data = np.loadtxt(veg_file, usecols=usecols, skiprows=skiprows)
10931093

tonic/models/vic/ncparam2ascii.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from scipy.spatial import cKDTree
1111
from . import grid_params
1212
from tonic.io import read_netcdf
13+
from tonic.pycompat import pyzip, iteritems
1314

1415
FILL_VALUE = -9999
1516

@@ -111,7 +112,7 @@ def rasm_soil(data, soil_file):
111112
numcells = data['mask'].size
112113

113114
arrayshape = (numcells, 1 + np.max([np.max(cols) for v, cols in
114-
c.soil_param.iteritems()]))
115+
iteritems(c.soil_param)]))
115116
soil_params = np.empty(arrayshape)
116117
dtypes = ['%1i'] * arrayshape[1]
117118
# ---------------------------------------------------------------- #
@@ -190,7 +191,7 @@ def rasm_soil(data, soil_file):
190191
# For rasm, all cols are shifted one to right to make room for nveg in
191192
# col 0
192193
i = -1
193-
for var, cols in c.soil_param.iteritems():
194+
for var, cols in iteritems(c.soil_param):
194195
for col in cols:
195196
dtypes[col] = f.soil_param[var]
196197

@@ -260,7 +261,7 @@ def rasm_soil(data, soil_file):
260261

261262
# ---------------------------------------------------------------- #
262263
# Print summary of variables
263-
for var, cols in c.soil_param.iteritems():
264+
for var, cols in iteritems(c.soil_param):
264265
print('{0: <12}--> min: {1:<09.3f}, max: {2:<09.3f}, mean:'
265266
' {3:<09.3f}'.format(var,
266267
soil_params[:, cols].min(),
@@ -361,7 +362,7 @@ def veg(data, xinds, yinds, veg_file, rootzones=3, global_lai=True):
361362

362363
f = open(veg_file, 'w')
363364

364-
for y, x in zip(yinds, xinds):
365+
for y, x in pyzip(yinds, xinds):
365366
gridcell = int(data['gridcell'][y, x])
366367
n_veg = int(data['Nveg'][y, x])
367368
cv = data['Cv'][:, y, x]

tonic/models/vic/netcdf2vic.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import struct
77
import os
88
from tonic.io import read_netcdf, read_config
9+
from tonic.pycompat import pyzip
910

1011
description = 'Convert netCDF meteorological forcings to VIC sytle format'
1112
help = 'Convert netCDF meteorological forcings to VIC sytle format'
@@ -47,7 +48,7 @@ def _run(args):
4748
xs[posinds] -= 360
4849
print('adjusted xs lon minimum')
4950

50-
for y, x in zip(yi, xi):
51+
for y, x in pyzip(yi, xi):
5152
active_flag = False
5253
for key in var_keys:
5354
if (d[key][:, y, x].all() is np.ma.masked) \
@@ -62,7 +63,7 @@ def _run(args):
6263
else:
6364
append = True
6465

65-
for y, x, point in zip(ylist, xlist, pointlist):
66+
for y, x, point in pyzip(ylist, xlist, pointlist):
6667

6768
data = np.empty((d[var_keys[0]].shape[0], len(var_keys)))
6869

tonic/models/vic/plot_params.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
import matplotlib.pyplot as plt
99
import matplotlib.gridspec as gridspec
1010
from mpl_toolkits.basemap import Basemap
11-
from share import read_netcdf
11+
from tonic.io import read_netcdf
12+
from tonic.pycompat import pyrange
1213
description = ''
1314
help = ''
1415

@@ -43,7 +44,7 @@ def plot_veg_types(yc, xc, cv, baresoil):
4344

4445
gs1 = gridspec.GridSpec(4, 3)
4546

46-
for loc in xrange(11):
47+
for loc in pyrange(11):
4748
ax = fig.add_subplot(gs1[loc])
4849
plot_map(ax, yc, xc, cv[loc], projection_parameters, vmin=0,
4950
cmap='Jet')

tonic/models/vic/vic2netcdf.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import time as tm
3434
from tonic.io import read_config, SafeConfigParser
3535
from tonic.tonic import calc_grid, get_grid_inds, NcVar
36+
from tonic.pycompat import pyzip, pyrange
3637

3738
description = 'Convert a set of VIC ascii outputs to gridded netCDF'
3839
help = 'Convert a set of VIC ascii outputs to gridded netCDF'
@@ -155,12 +156,12 @@ def get_lats(self):
155156
return np.array([p.lat for p in self])
156157

157158
def add_xs(self, xinds):
158-
for i in range(len(self)):
159+
for i in pyrange(len(self)):
159160
self[i].x = xinds[i]
160161
return
161162

162163
def add_ys(self, yinds):
163-
for i in range(len(self)):
164+
for i in pyrange(len(self)):
164165
self[i].y = yinds[i]
165166
return
166167

@@ -190,7 +191,7 @@ def set_fileformat(self, fileformat):
190191
elif fileformat == 'binary':
191192
p.open = p._open_binary
192193
p.read = p._read_binary
193-
p.dt = np.dtype(list(zip(p.names, p.bin_dtypes)))
194+
p.dt = np.dtype(list(pyzip(p.names, p.bin_dtypes)))
194195
elif fileformat == 'netcdf':
195196
p.open = p._open_netcdf
196197
p.read = p._read_netcdf
@@ -438,7 +439,7 @@ def nc_add_data_to_array(self, point):
438439
point.df[name].values[self.slice]
439440
for name in self.four_dim_vars:
440441
varshape = self.f.variables[name].shape[1]
441-
for i in range(varshape):
442+
for i in pyrange(varshape):
442443
subname = name + str(i)
443444
self.data[name][:, i, point.y,
444445
point.x] = point.df[subname].values[self.slice]
@@ -452,7 +453,7 @@ def nc_add_data_standard(self, points):
452453
self.f.variables[name][:, ys, xs] = data
453454
for name in self.four_dim_vars:
454455
varshape = self.f.variables[name].shape[1]
455-
for i in range(varshape):
456+
for i in pyrange(varshape):
456457
sn = name + str(i)
457458
self.f.variables[name][:, i, ys,
458459
xs] = p.df[sn].values[self.slice]
@@ -640,7 +641,7 @@ def vic2nc(options, global_atts, domain_dict, fields):
640641
+ end_date.month - start_date.month + 1
641642
month = start_date.month
642643
year = start_date.year
643-
for i in range(num_segments + 1):
644+
for i in pyrange(num_segments + 1):
644645
segment_dates.append(datetime(year, month, 1))
645646
month += 1
646647
if month == 13:
@@ -649,13 +650,13 @@ def vic2nc(options, global_atts, domain_dict, fields):
649650
elif options['time_segment'] == 'year':
650651
num_segments = end_date.year - start_date.year + 1
651652
year = start_date.year
652-
for i in range(num_segments + 1):
653+
for i in pyrange(num_segments + 1):
653654
segment_dates.append(datetime(year, 1, 1))
654655
year += 1
655656
elif options['time_segment'] == 'decade':
656657
num_segments = (end_date.year - start_date.year) / 10 + 1
657658
year = start_date.year
658-
for i in range(num_segments + 1):
659+
for i in pyrange(num_segments + 1):
659660
segment_dates.append(datetime(year, 1, 1))
660661
year += 10
661662
elif options['time_segment'] == 'all':
@@ -676,7 +677,7 @@ def vic2nc(options, global_atts, domain_dict, fields):
676677
# Setup Segments
677678
segments = deque()
678679

679-
for num in range(num_segments):
680+
for num in pyrange(num_segments):
680681
# Segment time bounds
681682
t0 = segment_dates[num]
682683
t1 = segment_dates[num + 1]
@@ -801,7 +802,7 @@ def vic2nc(options, global_atts, domain_dict, fields):
801802
# order. Note that sorted(usecols) is not strictly necessary, since
802803
# apparently that is done in read_table, but it keeps the names and columns
803804
# in the same order
804-
names = [x for (y, x) in sorted(zip(usecols, names))]
805+
names = [x for (y, x) in sorted(pyzip(usecols, names))]
805806
usecols = sorted(usecols)
806807
points.set_names(names)
807808
points.set_usecols(usecols)

tonic/pycompat.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import sys
2+
3+
PY3 = sys.version_info[0] >= 3
4+
5+
if PY3: # pragma: no cover
6+
basestring = str
7+
unicode_type = str
8+
bytes_type = bytes
9+
10+
def iteritems(d):
11+
return iter(d.items())
12+
13+
def itervalues(d):
14+
return iter(d.values())
15+
16+
pyrange = range
17+
pyzip = zip
18+
from functools import reduce as pyreduce
19+
import builtins
20+
from configparser import SafeConfigParser
21+
else: # pragma: no cover
22+
# Python 2
23+
basestring = basestring
24+
unicode_type = unicode
25+
bytes_type = str
26+
27+
def iteritems(d):
28+
return d.iteritems()
29+
30+
def itervalues(d):
31+
return d.itervalues()
32+
33+
pyrange = xrange
34+
from itertools import izip as pyzip
35+
from itertools import imap as pymap
36+
pyreduce = reduce
37+
import __builtin__ as builtins
38+
from ConfigParser import SafeConfigParser
39+
try:
40+
from cyordereddict import OrderedDict
41+
except ImportError: # pragma: no cover
42+
try:
43+
from collections import OrderedDict
44+
except ImportError:
45+
from ordereddict import OrderedDict

0 commit comments

Comments
 (0)