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: 3 additions & 2 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ h5netcdf
matplotlib
pytest
flake8
numpy
pandas
numpy>=1.2,<2
pandas<3
scipy
pyyaml
netcdf4
xarray
pyproj
packaging
sphinx
sphinx-rtd-theme
sphinx-gallery
Expand Down
6 changes: 5 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def find_data():
]

requires_list = [
'numpy>=1.2', 'netCDF4', 'scipy', 'matplotlib', 'pyyaml', 'pandas',
'numpy>=1.2,<2', 'netCDF4', 'scipy', 'matplotlib', 'pyyaml', 'pandas<3', 'packaging'
]

if sys.version_info.major == 3:
Expand Down Expand Up @@ -109,6 +109,10 @@ def find_data():
url='http://github.com/barronh/pseudonetcdf/',
classifiers=[
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Operating System :: MacOS',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX',
Expand Down
2 changes: 0 additions & 2 deletions src/PseudoNetCDF/_getreader.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ def getreader(*args, **kwds):
-------
reader : class
"""
global _readers
format = kwds.pop('format', None)
if not os.path.isfile(args[0]):
warn(('The first argument (%s) does not exist as a file. ' +
Expand Down Expand Up @@ -71,7 +70,6 @@ def checker(*args, **kwds):


def registerreader(name, reader):
global _readers, pncopen
if name not in [k for k, v in _readers]:
_readers.insert(0, (name, reader))
if pncopen.__doc__ is not None:
Expand Down
1 change: 0 additions & 1 deletion src/PseudoNetCDF/_getwriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ def testwriter(writer, *args, **kwds):


def registerwriter(name, writer):
global _writers
_writers.insert(0, (name, writer))


Expand Down
24 changes: 12 additions & 12 deletions src/PseudoNetCDF/coordutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,9 +423,9 @@ def wrapper(first, instr):
""" % outdict


def getprojwkt(ifile, withgrid=False):
def getprojwkt(ifile, withgrid=False, fromorigin=False):
import osr
proj4str = getproj4(ifile, withgrid=withgrid)
proj4str = getproj4(ifile, withgrid=withgrid, fromorigin=fromorigin)

srs = osr.SpatialReference()
# Imports WKT to Spatial Reference Object
Expand All @@ -434,11 +434,11 @@ def getprojwkt(ifile, withgrid=False):
return srs.ExportToWkt()


def basemap_from_file(ifile, withgrid=False, **kwds):
def basemap_from_file(ifile, withgrid=False, fromorigin=False, **kwds):
"""
Typically, the user will need to provide some options
"""
proj4 = getproj4(ifile, withgrid=withgrid)
proj4 = getproj4(ifile, withgrid=withgrid, fromorigin=fromorigin)
basemap_options = basemap_options_from_proj4(proj4, **kwds)
if 'llcrnrx' in basemap_options:
if 'urcrnrx' in kwds:
Expand Down Expand Up @@ -522,7 +522,7 @@ def basemap_from_proj4(proj4, **kwds):
return bmap


def getproj4_from_cf_var(gridmapping, withgrid=False):
def getproj4_from_cf_var(gridmapping, withgrid=False, fromorigin=False):
mapstr_bits = OrderedDict()
gname = getattr(gridmapping, 'grid_mapping_name')
pv4s = dict(lambert_conformal_conic='lcc',
Expand Down Expand Up @@ -558,9 +558,9 @@ def getproj4_from_cf_var(gridmapping, withgrid=False):
mapstr_bits['lon_0'] = pv
elif pk == 'latitude_of_projection_origin':
mapstr_bits['lat_0'] = pv
elif pk == 'false_easting':
elif pk == 'false_easting' and not fromorigin:
mapstr_bits['x_0'] = pv
elif pk == 'false_northing':
elif pk == 'false_northing' and not fromorigin:
mapstr_bits['y_0'] = pv
elif pk == 'scale_factor_at_projection_origin':
mapstr_bits['k_0'] = pv
Expand Down Expand Up @@ -588,17 +588,17 @@ def getproj4_from_cf_var(gridmapping, withgrid=False):
return mapstr


def getproj(ifile, withgrid=False):
def getproj(ifile, withgrid=False, fromorigin=False):
import pyproj
proj4str = getproj4(ifile, withgrid=withgrid)
proj4str = getproj4(ifile, withgrid=withgrid, fromorigin=fromorigin)
preserve_units = withgrid
# pyproj adds +units=m, which is not right for latlon/lonlat
if '+proj=lonlat' in proj4str or '+proj=latlon' in proj4str:
preserve_units = True
return pyproj.Proj(proj4str, preserve_units=preserve_units)


def getproj4(ifile, withgrid=False):
def getproj4(ifile, withgrid=False, fromorigin=False):
"""
Arguments:
ifile - PseudoNetCDF file
Expand All @@ -614,7 +614,7 @@ def getproj4(ifile, withgrid=False):
for k in 'P_GAM P_ALP P_BET XORIG YORIG XCELL YCELL'.split()])
):
gridmapping = getmapdef(ifile, add=False)
mapstr = getproj4_from_cf_var(gridmapping, withgrid=withgrid)
mapstr = getproj4_from_cf_var(gridmapping, withgrid=withgrid, fromorigin=fromorigin)
if withgrid:
dx = min(ifile.XCELL, ifile.YCELL)
if ifile.XCELL != ifile.YCELL:
Expand Down Expand Up @@ -656,7 +656,7 @@ def getproj4(ifile, withgrid=False):
mapstr = '+proj=lonlat'
else:
gridmapping = ifile.variables[gridmappings[0]]
mapstr = getproj4_from_cf_var(gridmapping, withgrid=withgrid)
mapstr = getproj4_from_cf_var(gridmapping, withgrid=withgrid, fromorigin=fromorigin)
else:
warn('No known grid mapping; assuming lonlat')
mapstr = '+proj=lonlat'
Expand Down
18 changes: 14 additions & 4 deletions src/PseudoNetCDF/core/_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ class PseudoNetCDFFile(PseudoNetCDFSelfReg, object):
methods that a file should present to act like a netCDF file
using the Scientific.IO.NetCDF.NetCDFFile interface.
"""
def xarray(self):
import xarray as xr
data_vars = {
k: v.xarray() for k, v in self.variables.items()
if k not in self.dimensions
}
attrs = {k: self.getncattr(k) for k in self.ncattrs()}
return xr.Dataset(data_vars, attrs=attrs)

def getMap(self, maptype='basemap_auto', **kwds):
"""
Expand Down Expand Up @@ -113,7 +121,7 @@ def getMap(self, maptype='basemap_auto', **kwds):
raise ValueError(
'maptype must be basemap, basemap_auto, or cartopy')

def getproj(self, withgrid=False, projformat='pyproj'):
def getproj(self, withgrid=False, projformat='pyproj', fromorigin=False):
"""
Description

Expand All @@ -125,6 +133,8 @@ def getproj(self, withgrid=False, projformat='pyproj'):
'pyproj' (default), 'proj4' or 'wkt' allows function to
return a pyproj projection object or a string in the
format of proj4 or WKT
fromorigin : boolean
Ignore false easting and false northing offsets

Returns
-------
Expand All @@ -133,13 +143,13 @@ def getproj(self, withgrid=False, projformat='pyproj'):
"""
if projformat == 'pyproj':
from PseudoNetCDF.coordutil import getproj
return getproj(self, withgrid=withgrid)
return getproj(self, withgrid=withgrid, fromorigin=fromorigin)
elif projformat == 'proj4':
from PseudoNetCDF.coordutil import getproj4
return getproj4(self, withgrid=withgrid)
return getproj4(self, withgrid=withgrid, fromorigin=fromorigin)
elif projformat == 'wkt':
from PseudoNetCDF.coordutil import getprojwkt
return getprojwkt(self, withgrid=withgrid)
return getprojwkt(self, withgrid=withgrid, fromorigin=fromorigin)
else:
raise ValueError('projformat must be pyproj, proj4 or wkt')

Expand Down
2 changes: 1 addition & 1 deletion src/PseudoNetCDF/core/_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def get_coord(self, coordn):
coordi = list(self.dimensions).index(coordn)
coordv = np.arange(self.shape[coordi])
else:
coordv = (v.dimensions, v.xarray(iscoord=True))
coordv = (v.dimensions, v.array())
else:
coordi = list(self.dimensions).index(coordn)
coordv = np.arange(self.shape[coordi])
Expand Down
2 changes: 0 additions & 2 deletions src/PseudoNetCDF/plotutil/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@


def get_norm(name):
global _registered_norms
return _registered_norms[name]


def register_norm(name, norm):
global _registered_norms
if isinstance(norm, Normalize):
_registered_norms[name] = norm
else:
Expand Down
1 change: 0 additions & 1 deletion src/PseudoNetCDF/pncwarn.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ def warn(*args, **kwds):

def clean_showwarning(message, category, filename, lineno, file=None,
line=None):
global _first_read_only
if file is None:
file = sys.stderr
if file is None:
Expand Down
7 changes: 6 additions & 1 deletion src/PseudoNetCDF/test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ def _importorskip(modname, minversion=None):
try:
from packaging.version import Version
except Exception:
from distutils.version import LooseVersion as Version
msg = 'packaging (python>=3.8) was not available.'
try:
from distutils.version import LooseVersion as Version
except Exception:
msg += ' distutils (python<3.12) was not available'
raise ImportError(msg)
try:
mod = importlib.import_module(modname)
has = True
Expand Down
43 changes: 23 additions & 20 deletions src/PseudoNetCDF/test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,7 @@ def testNetcdf(self):
del cncf
os.remove(tmppath)

@unittest.skip('Flaky with parallel netCDF4>=1.6')
def testOpenMFDataset(self):
import tempfile
import os
Expand All @@ -936,26 +937,28 @@ def testOpenMFDataset(self):

tncf = self.testncf.copy()
to3 = tncf.variables['O3'][:]
tmpdirname = tempfile.gettempdir()
tmppath1 = os.path.join(tmpdirname, 'test1.nc')
tmppath2 = os.path.join(tmpdirname, 'test2.nc')
tncf.save(tmppath1).close()
tncf.save(tmppath2).close()
nt = len(tncf.dimensions['TSTEP'])
cncf = netcdf.open_mfdataset(tmppath1, tmppath2, stackdim='TSTEP')
np_all_close(cncf.variables['O3'][:nt], to3)
np_all_close(cncf.variables['O3'][nt:], to3)
cncf.close()
# to ensure compatibility with windows, removing any references to
# underlying files so they can be deleted.
del cncf
gc.collect()
try:
os.remove(tmppath1)
os.remove(tmppath2)
except Exception:
warnings.warn(f'Could not delete {tmppath1} and {tmppath2}')
pass
with tempfile.TemporaryDirectory() as tmpdirname:
tmppath1 = os.path.join(tmpdirname, 'test1.nc')
tmppath2 = os.path.join(tmpdirname, 'test2.nc')
tncf.save(tmppath1).close()
tncf.save(tmppath2).close()
nt = len(tncf.dimensions['TSTEP'])

cncf = netcdf.open_mfdataset(tmppath1, tmppath2, stackdim='TSTEP')
np_all_close(cncf.variables['O3'][:nt], to3)
np_all_close(cncf.variables['O3'][nt:], to3)
cncf.close()

# to ensure compatibility with windows, removing any references to
# underlying files so they can be deleted.
del cncf
gc.collect()
try:
os.remove(tmppath1)
os.remove(tmppath2)
except Exception:
warnings.warn(f'Could not delete {tmppath1} and {tmppath2}')
pass

def runTest(self):
pass
10 changes: 6 additions & 4 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@ envlist = py{36,39,311,312}
[coverage:run]
omit = none

[flake8]
exclude = .ipynb_checkpoints
ignore = E501,W504,W503

[testenv]
# install pytest in the virtualenv where commands will be executed
deps =
pytest
flake8
coverage

commands =
# NOTE: you can run any command line tool here - not just tests
flake8 --ignore=W503,W504 src/PseudoNetCDF
coverage run -m pytest
coverage report -i
flake8 src/PseudoNetCDF
python -m pytest -v src/PseudoNetCDF

[gh-actions]
python =
Expand Down