diff --git a/autotest/t032_test.py b/autotest/t032_test.py index 5d962f7e71..dd2423ffac 100644 --- a/autotest/t032_test.py +++ b/autotest/t032_test.py @@ -2,13 +2,6 @@ Test shapefile stuff """ import os - -# python < 3.4 (reload in default namespace) -try: - from importlib import reload -except: - from imp import reload - import shutil import numpy as np import flopy @@ -53,9 +46,8 @@ def test_polygon_from_ij(): assert np.abs(geoms[0].bounds[-1] - 5169784.473861726) < 1e-4 fpth = os.path.join(mpth, 'test.shp') recarray2shp(recarray, geoms, fpth, epsg=26715) - import epsgref - reload(epsgref) - from epsgref import prj + ep = epsgRef() + prj = ep.to_dict() assert 26715 in prj fpth = os.path.join(mpth, 'test.prj') fpth2 = os.path.join(mpth, '26715.prj') @@ -77,28 +69,20 @@ def test_epsgref(): ep = epsgRef() ep.reset() - import epsgref getprj(4326) - reload(epsgref) - from epsgref import prj + prj = ep.to_dict() assert 4326 in prj ep.add(9999, 'junk') - ep._remove_pyc() # have to do this in python 2, otherwise won't refresh - reload(epsgref) - from epsgref import prj + prj = ep.to_dict() assert 9999 in prj ep.remove(9999) - ep._remove_pyc() - reload(epsgref) - from epsgref import prj + prj = ep.to_dict() assert 9999 not in prj ep.reset() - ep._remove_pyc() - reload(epsgref) - from epsgref import prj + prj = ep.to_dict() assert len(prj) == 0 diff --git a/examples/Notebooks/flopy3_shapefile_features.ipynb b/examples/Notebooks/flopy3_shapefile_features.ipynb index ea14264cbd..fec954531c 100644 --- a/examples/Notebooks/flopy3_shapefile_features.ipynb +++ b/examples/Notebooks/flopy3_shapefile_features.ipynb @@ -36,13 +36,6 @@ "%matplotlib inline\n", "import os\n", "import sys\n", - "\n", - "# python < 3.4 (reload in default namespace)\n", - "try:\n", - " from importlib import reload\n", - "except:\n", - " from imp import reload\n", - "\n", "import shutil\n", "import numpy as np\n", "import matplotlib as mpl\n", @@ -374,9 +367,8 @@ "source": [ "### How the epsg feature works \n", "* requires an internet connection the first time to get the prj text from [spatialreference.org](http://spatialreference.org/) using ```requests``` \n", - "* if it doesn't exist, ```epsgref.py``` is created in the site-packages folder \n", - "* the prj text is then stashed in this file as an entry in a dictionary ```prj``` \n", - "* this dictionary is imported and checked for the prjtext each time flopy.utils.reference.getprj is called" + "* if it doesn't exist, ```epsgref.json``` is created in the user's data directory\n", + "* the prj text is then stashed in this JSON file hashed by the EPSG numeric code" ] }, { @@ -387,7 +379,8 @@ { "data": { "text/plain": [ - "{26715: 'PROJCS[\"NAD_1927_UTM_Zone_15N\",GEOGCS[\"GCS_North_American_1927\",DATUM[\"D_North_American_1927\",SPHEROID[\"Clarke_1866\",6378206.4,294.9786982138982]],PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.017453292519943295]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",-93],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],UNIT[\"Meter\",1]]'}" + "OrderedDict([(26715,\n", + " 'PROJCS[\"NAD_1927_UTM_Zone_15N\",GEOGCS[\"GCS_North_American_1927\",DATUM[\"D_North_American_1927\",SPHEROID[\"Clarke_1866\",6378206.4,294.9786982138982]],PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.017453292519943295]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",-93],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],UNIT[\"Meter\",1]]')])" ] }, "execution_count": 14, @@ -396,9 +389,9 @@ } ], "source": [ - "import epsgref\n", - "reload(epsgref)\n", - "from epsgref import prj\n", + "from flopy.utils.reference import epsgRef\n", + "ep = epsgRef()\n", + "prj = ep.to_dict()\n", "prj" ] }, @@ -450,8 +443,7 @@ } ], "source": [ - "reload(epsgref)\n", - "from epsgref import prj\n", + "prj = ep.to_dict()\n", "for k, v in prj.items():\n", " print('{}:\\n{}\\n'.format(k, v))" ] @@ -495,6 +487,9 @@ "\n", "4326:\n", "GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137,298.257223563]],PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.017453292519943295]]\n", + "\n", + "9999:\n", + "junk\n", "\n" ] } @@ -549,7 +544,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Resetting /anaconda3/lib/python3.6/site-packages/epsgref.py\n" + "Resetting /home/jdhughes/.local/share/flopy/epsgref.json\n" ] } ], @@ -565,7 +560,7 @@ { "data": { "text/plain": [ - "{}" + "OrderedDict()" ] }, "execution_count": 23, @@ -574,8 +569,7 @@ } ], "source": [ - "reload(epsgref)\n", - "from epsgref import prj\n", + "prj = ep.to_dict()\n", "prj" ] }, diff --git a/flopy/export/shapefile_utils.py b/flopy/export/shapefile_utils.py index 7060e5acd9..1b66a0f5b1 100755 --- a/flopy/export/shapefile_utils.py +++ b/flopy/export/shapefile_utils.py @@ -399,7 +399,7 @@ def recarray2shp(recarray, geoms, shpname='recarray.shp', epsg=None, prj=None, Uses pyshp. epsg code requires an internet connection the first time to get the projection file text from spatialreference.org, but then stashes the text in the file - epsgref.py (located in the site-packages folder) for subsequent use. See + epsgref.json (located in the user's data directory) for subsequent use. See flopy.reference for more details. """ diff --git a/flopy/utils/reference.py b/flopy/utils/reference.py index 00487690fc..2fbf3e898a 100755 --- a/flopy/utils/reference.py +++ b/flopy/utils/reference.py @@ -2,9 +2,11 @@ Module spatial referencing for flopy model objects """ -import sys -import os +import json import numpy as np +import os + +from collections import OrderedDict class SpatialReference(object): @@ -1803,58 +1805,76 @@ def model_time_units(self): class epsgRef: - """Sets up a local database of projection file text referenced by epsg code. - The database is located in the site packages folder in epsgref.py, which - contains a dictionary, prj, of projection file text keyed by epsg value. + """Sets up a local database of text representations of coordinate reference + systems, keyed by EPSG code. + + The database is epsgref.json, located in the user's data directory. If + optional 'appdirs' package is available, this is in the platform-dependent + user directory, otherwise in the user's 'HOME/.flopy' directory. """ def __init__(self): - sp = [f for f in sys.path if f.endswith('site-packages')][0] - self.location = os.path.join(sp, 'epsgref.py') - - def _remove_pyc(self): - try: # get rid of pyc file - os.remove(self.location + 'c') - except: - pass + try: + from appdirs import user_data_dir + except ImportError: + user_data_dir = None + if user_data_dir: + datadir = user_data_dir('flopy') + else: + # if appdirs is not installed, use user's home directory + datadir = os.path.join(os.path.expanduser('~'), '.flopy') + if not os.path.isdir(datadir): + os.makedirs(datadir) + dbname = 'epsgref.json' + self.location = os.path.join(datadir, dbname) + + def to_dict(self): + """Returns dict with EPSG code integer key, and WKT CRS text""" + data = OrderedDict() + if os.path.exists(self.location): + with open(self.location, 'r') as f: + loaded_data = json.load(f, object_pairs_hook=OrderedDict) + # convert JSON key from str to EPSG integer + for key, value in loaded_data.items(): + try: + data[int(key)] = value + except ValueError: + data[key] = value + return data - def make(self): - if not os.path.exists(self.location): - newfile = open(self.location, 'w') - newfile.write('prj = {}\n') - newfile.close() + def _write(self, data): + with open(self.location, 'w') as f: + json.dump(data, f, indent=0) + f.write('\n') def reset(self, verbose=True): if os.path.exists(self.location): os.remove(self.location) - self._remove_pyc() - self.make() if verbose: print('Resetting {}'.format(self.location)) def add(self, epsg, prj): - """add an epsg code to epsgref.py""" - with open(self.location, 'a') as epsgfile: - epsgfile.write("prj[{:d}] = '{}'\n".format(epsg, prj)) + """add an epsg code to epsgref.json""" + data = self.to_dict() + data[epsg] = prj + self._write(data) + + def get(self, epsg): + """returns prj from a epsg code, otherwise None if not found""" + data = self.to_dict() + return data.get(epsg) def remove(self, epsg): - """removes an epsg entry from epsgref.py""" - from epsgref import prj - self.reset(verbose=False) - if epsg in prj.keys(): - del prj[epsg] - for epsg, prj in prj.items(): - self.add(epsg, prj) + """removes an epsg entry from epsgref.json""" + data = self.to_dict() + if epsg in data: + del data[epsg] + self._write(data) @staticmethod def show(): - try: - from importlib import reload - except: - from imp import reload - import epsgref - from epsgref import prj - reload(epsgref) + ep = epsgRef() + prj = ep.to_dict() for k, v in prj.items(): print('{}:\n{}\n'.format(k, v)) @@ -2050,7 +2070,7 @@ def getprj(epsg, addlocalreference=True, text='esriwkt'): epsg code for coordinate system addlocalreference : boolean adds the projection file text associated with epsg to a local - database, epsgref.py, located in site-packages. + database, epsgref.json, located in the user's data directory. References ---------- @@ -2062,12 +2082,7 @@ def getprj(epsg, addlocalreference=True, text='esriwkt'): text for a projection (*.prj) file. """ epsgfile = epsgRef() - wktstr = None - try: - from epsgref import prj - wktstr = prj.get(epsg) - except: - epsgfile.make() + wktstr = epsgfile.get(epsg) if wktstr is None: wktstr = get_spatialreference(epsg, text=text) if addlocalreference and wktstr is not None: diff --git a/requirements.travis.txt b/requirements.travis.txt index add0925d68..326f5e51b2 100644 --- a/requirements.travis.txt +++ b/requirements.travis.txt @@ -1,3 +1,4 @@ +appdirs matplotlib netcdf4 fiona diff --git a/requirements2-34.travis.txt b/requirements2-34.travis.txt index 9917feb640..8a14fb8e7a 100644 --- a/requirements2-34.travis.txt +++ b/requirements2-34.travis.txt @@ -1,3 +1,4 @@ +appdirs matplotlib netcdf4<1.2.8 fiona