Skip to content

Remove networking code from iotools.read_tmy3, tkinter from read_tmy2/3 #1004

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

Merged
merged 8 commits into from
Jul 19, 2020
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
10 changes: 9 additions & 1 deletion docs/sphinx/source/whatsnew/v0.8.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
~~~~~~~~~~~~
Expand Down
68 changes: 14 additions & 54 deletions pvlib/iotools/tmy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,26 @@
"""

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
use of the updated files.

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
Expand Down Expand Up @@ -161,46 +158,25 @@ 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'])
meta['longitude'] = float(meta['longitude'])
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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
-------
Expand Down Expand Up @@ -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
Expand Down
11 changes: 2 additions & 9 deletions pvlib/tests/iotools/test_tmy.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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)

Expand Down