diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index cd1e50d5e9..b15911ef7e 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -16,7 +16,15 @@ API Changes with Deprecations API Changes ~~~~~~~~~~~ * Removed ``run_parallel_calculations`` and ``n_workers_for_parallel_calcs`` - from :py:func:`pvlib.bifacial.pvfactors_timeseries` inputs (:issue:`902`)(:pull:`934`) + from :py:func:`pvlib.bifacial.pvfactors_timeseries` inputs (:issue:`902`) (:pull:`934`) +* :py:func:`pvlib.iotools.read_tmy3` can now only read local data files because + the NREL RREDC server hosting the TMY3 dataset has been retired. For + fetching TMY data from NREL servers, :py:func:`pvlib.iotools.get_psm3` is + now recommended to retrieve newer PSM3 data over the older TMY3 data. + (:issue:`996`) (:pull:`1004`) +* The tkinter-based file selection dialog has been removed from + :py:func:`pvlib.iotools.read_tmy2` and :py:func:`pvlib.iotools.read_tmy3`; + the filepath is now a required parameter. (:pull:`1004`) Enhancements ~~~~~~~~~~~~ diff --git a/pvlib/iotools/tmy.py b/pvlib/iotools/tmy.py index 3b9a501fa8..0f43aa83bb 100644 --- a/pvlib/iotools/tmy.py +++ b/pvlib/iotools/tmy.py @@ -3,19 +3,17 @@ """ import datetime -import io import re -from urllib.request import urlopen, Request import pandas as pd -def read_tmy3(filename=None, coerce_year=None, recolumn=True): +def read_tmy3(filename, coerce_year=None, recolumn=True): ''' Read a TMY3 file in to a pandas dataframe. Note that values contained in the metadata dictionary are unchanged from the TMY3 file (i.e. units are retained). In the case of any - discrepencies between this documentation and the TMY3 User's Manual + discrepancies between this documentation and the TMY3 User's Manual [1]_, the TMY3 User's Manual takes precedence. The TMY3 files were updated in Jan. 2015. This function requires the @@ -23,9 +21,8 @@ def read_tmy3(filename=None, coerce_year=None, recolumn=True): Parameters ---------- - filename : None or string, default None - If None, attempts to use a Tkinter file browser. A string can be - a relative file path, absolute file path, or url. + filename : str + A relative file path or absolute file path. coerce_year : None or int, default None If supplied, the year of the index will be set to `coerce_year`, except @@ -161,34 +158,18 @@ def read_tmy3(filename=None, coerce_year=None, recolumn=True): Update: Users Manual. 472 pp.; NREL Report No. TP-581-41364. ''' - if filename is None: - try: - filename = _interactive_load() - except ImportError: - raise ImportError('Interactive load failed. tkinter not supported ' - 'on this system. Try installing X-Quartz and ' - 'reloading') - head = ['USAF', 'Name', 'State', 'TZ', 'latitude', 'longitude', 'altitude'] - if str(filename).startswith('http'): - request = Request(filename, headers={'User-Agent': ( - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) ' - 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 ' - 'Safari/537.36')}) - response = urlopen(request) - csvdata = io.StringIO(response.read().decode(errors='ignore')) - else: - # assume it's accessible via the file system - csvdata = open(str(filename), 'r') - - # read in file metadata, advance buffer to second line - firstline = csvdata.readline() - if 'Request Rejected' in firstline: - raise IOError('Remote server rejected TMY file request') + with open(str(filename), 'r') as csvdata: + # read in file metadata, advance buffer to second line + firstline = csvdata.readline() + # use pandas to read the csv file buffer + # header is actually the second line, but tell pandas to look for + # header information on the 1st line (0 indexing) because we've already + # advanced past the true first line with the readline call above. + data = pd.read_csv(csvdata, header=0) meta = dict(zip(head, firstline.rstrip('\n').split(","))) - # convert metadata strings to numeric types meta['altitude'] = float(meta['altitude']) meta['latitude'] = float(meta['latitude']) @@ -196,11 +177,6 @@ def read_tmy3(filename=None, coerce_year=None, recolumn=True): meta['TZ'] = float(meta['TZ']) meta['USAF'] = int(meta['USAF']) - # use pandas to read the csv file/stringio buffer - # header is actually the second line in file, but tell pandas to look for - # header information on the 1st line (0 indexing) because we've already - # advanced past the true first line with the readline call above. - data = pd.read_csv(csvdata, header=0) # get the date column as a pd.Series of numpy datetime64 data_ymd = pd.to_datetime(data['Date (MM/DD/YYYY)'], format='%m/%d/%Y') # shift the time column so that midnite is 00:00 instead of 24:00 @@ -231,13 +207,6 @@ def read_tmy3(filename=None, coerce_year=None, recolumn=True): return data, meta -def _interactive_load(): - import tkinter - from tkinter.filedialog import askopenfilename - tkinter.Tk().withdraw() # Start interactive file input - return askopenfilename() - - def _recolumn(tmy3_dataframe): """ Rename the columns of the TMY3 DataFrame. @@ -295,9 +264,8 @@ def read_tmy2(filename): Parameters ---------- - filename : None or string - If None, attempts to use a Tkinter file browser. A string can be - a relative file path, absolute file path, or url. + filename : str + A relative or absolute file path. Returns ------- @@ -412,14 +380,6 @@ def read_tmy2(filename): for TMY2s". NREL 1995. ''' - if filename is None: - try: - filename = _interactive_load() - except ImportError: - raise ImportError('Interactive load failed. tkinter not supported ' - 'on this system. Try installing X-Quartz and ' - 'reloading') - # paste in the column info as one long line string = '%2d%2d%2d%2d%4d%4d%4d%1s%1d%4d%1s%1d%4d%1s%1d%4d%1s%1d%4d%1s%1d%4d%1s%1d%4d%1s%1d%2d%1s%1d%2d%1s%1d%4d%1s%1d%4d%1s%1d%3d%1s%1d%4d%1s%1d%3d%1s%1d%3d%1s%1d%4d%1s%1d%5d%1s%1d%10d%3d%1s%1d%3d%1s%1d%3d%1s%1d%2d%1s%1d' # noqa: E501 columns = 'year,month,day,hour,ETR,ETRN,GHI,GHISource,GHIUncertainty,DNI,DNISource,DNIUncertainty,DHI,DHISource,DHIUncertainty,GHillum,GHillumSource,GHillumUncertainty,DNillum,DNillumSource,DNillumUncertainty,DHillum,DHillumSource,DHillumUncertainty,Zenithlum,ZenithlumSource,ZenithlumUncertainty,TotCld,TotCldSource,TotCldUncertainty,OpqCld,OpqCldSource,OpqCldUncertainty,DryBulb,DryBulbSource,DryBulbUncertainty,DewPoint,DewPointSource,DewPointUncertainty,RHum,RHumSource,RHumUncertainty,Pressure,PressureSource,PressureUncertainty,Wdir,WdirSource,WdirUncertainty,Wspd,WspdSource,WspdUncertainty,Hvis,HvisSource,HvisUncertainty,CeilHgt,CeilHgtSource,CeilHgtUncertainty,PresentWeather,Pwat,PwatSource,PwatUncertainty,AOD,AODSource,AODUncertainty,SnowDepth,SnowDepthSource,SnowDepthUncertainty,LastSnowfall,LastSnowfallSource,LastSnowfallUncertaint' # noqa: E501 diff --git a/pvlib/tests/iotools/test_tmy.py b/pvlib/tests/iotools/test_tmy.py index 98971005e3..566744c702 100644 --- a/pvlib/tests/iotools/test_tmy.py +++ b/pvlib/tests/iotools/test_tmy.py @@ -1,8 +1,7 @@ import numpy as np import pandas as pd -import pytest from pvlib.iotools import tmy -from conftest import DATA_DIR, RERUNS, RERUNS_DELAY +from conftest import DATA_DIR # test the API works from pvlib.iotools import read_tmy3 @@ -16,13 +15,6 @@ def test_read_tmy3(): tmy.read_tmy3(TMY3_TESTFILE) -@pytest.mark.remote_data -@pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY) -def test_read_tmy3_remote(): - url = 'http://rredc.nrel.gov/solar/old_data/nsrdb/1991-2005/data/tmy3/703165TYA.CSV' - tmy.read_tmy3(url) - - def test_read_tmy3_recolumn(): data, meta = tmy.read_tmy3(TMY3_TESTFILE) assert 'GHISource' in data.columns @@ -47,6 +39,7 @@ def test_read_tmy3_no_coerce_year(): assert data.index[-2] == pd.Timestamp('1998-12-31 23:00:00-09:00') assert data.index[-1] == pd.Timestamp('1999-01-01 00:00:00-09:00') + def test_read_tmy2(): tmy.read_tmy2(TMY2_TESTFILE)