Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f33be83

Browse filesBrowse files
Deprecate parse_psm3 and parse_cams (#2458)
* deprecate parse_psm3 * deprecate parse_cams * whatsnew * lint * Update docs/sphinx/source/whatsnew/v0.12.1.rst Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com> * lint --------- Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com>
1 parent 0cf6c8a commit f33be83
Copy full SHA for f33be83

File tree

Expand file treeCollapse file tree

5 files changed

+98
-135
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+98
-135
lines changed

‎docs/sphinx/source/whatsnew/v0.12.1.rst

Copy file name to clipboardExpand all lines: docs/sphinx/source/whatsnew/v0.12.1.rst
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ Breaking Changes
88
~~~~~~~~~~~~~~~~
99

1010

11+
Deprecations
12+
~~~~~~~~~~~~
13+
* The following ``parse_`` functions in :py:mod:`pvlib.iotools` are deprecated,
14+
with the corresponding ``read_`` functions taking their place: (:issue:`2444`, :pull:`2458`)
15+
16+
- :py:func:`~pvlib.iotools.parse_psm3`
17+
- :py:func:`~pvlib.iotools.parse_cams`
18+
19+
1120
Bug fixes
1221
~~~~~~~~~
1322
* :py:func:`pvlib.iotools.get_pvgis_tmy` now returns the correct dtypes when

‎pvlib/iotools/psm3.py

Copy file name to clipboardExpand all lines: pvlib/iotools/psm3.py
+37-71Lines changed: 37 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import requests
88
import pandas as pd
99
from json import JSONDecodeError
10-
import warnings
11-
from pvlib._deprecation import pvlibDeprecationWarning
10+
from pvlib._deprecation import deprecated
11+
from pvlib import tools
1212

1313
NSRDB_API_BASE = "https://developer.nrel.gov"
1414
PSM_URL = NSRDB_API_BASE + "/api/nsrdb/v2/solar/psm3-2-2-download.csv"
@@ -127,7 +127,7 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
127127
timeseries data from NREL PSM3
128128
metadata : dict
129129
metadata from NREL PSM3 about the record, see
130-
:func:`pvlib.iotools.parse_psm3` for fields
130+
:func:`pvlib.iotools.read_psm3` for fields
131131
132132
Raises
133133
------
@@ -152,7 +152,7 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
152152
153153
See Also
154154
--------
155-
pvlib.iotools.read_psm3, pvlib.iotools.parse_psm3
155+
pvlib.iotools.read_psm3
156156
157157
References
158158
----------
@@ -216,12 +216,12 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
216216
# the CSV is in the response content as a UTF-8 bytestring
217217
# to use pandas we need to create a file buffer from the response
218218
fbuf = io.StringIO(response.content.decode('utf-8'))
219-
return parse_psm3(fbuf, map_variables)
219+
return read_psm3(fbuf, map_variables)
220220

221221

222-
def parse_psm3(fbuf, map_variables=True):
222+
def read_psm3(filename, map_variables=True):
223223
"""
224-
Parse an NSRDB PSM3 weather file (formatted as SAM CSV). The NSRDB
224+
Read an NSRDB PSM3 weather file (formatted as SAM CSV). The NSRDB
225225
is described in [1]_ and the SAM CSV format is described in [2]_.
226226
227227
.. versionchanged:: 0.9.0
@@ -231,8 +231,8 @@ def parse_psm3(fbuf, map_variables=True):
231231
232232
Parameters
233233
----------
234-
fbuf: file-like object
235-
File-like object containing data to read.
234+
filename: str, path-like, or buffer
235+
Filename or in-memory buffer of a file containing data to read.
236236
map_variables: bool, default True
237237
When true, renames columns of the Dataframe to pvlib variable names
238238
where applicable. See variable :const:`VARIABLE_MAP`.
@@ -302,12 +302,15 @@ def parse_psm3(fbuf, map_variables=True):
302302
Examples
303303
--------
304304
>>> # Read a local PSM3 file:
305+
>>> df, metadata = iotools.read_psm3("data.csv") # doctest: +SKIP
306+
307+
>>> # Read a file object or an in-memory buffer:
305308
>>> with open(filename, 'r') as f: # doctest: +SKIP
306-
... df, metadata = iotools.parse_psm3(f) # doctest: +SKIP
309+
... df, metadata = iotools.read_psm3(f) # doctest: +SKIP
307310
308311
See Also
309312
--------
310-
pvlib.iotools.read_psm3, pvlib.iotools.get_psm3
313+
pvlib.iotools.get_psm3
311314
312315
References
313316
----------
@@ -316,34 +319,35 @@ def parse_psm3(fbuf, map_variables=True):
316319
.. [2] `Standard Time Series Data File Format
317320
<https://web.archive.org/web/20170207203107/https://sam.nrel.gov/sites/default/files/content/documents/pdf/wfcsv.pdf>`_
318321
"""
319-
# The first 2 lines of the response are headers with metadata
320-
metadata_fields = fbuf.readline().split(',')
321-
metadata_fields[-1] = metadata_fields[-1].strip() # strip trailing newline
322-
metadata_values = fbuf.readline().split(',')
323-
metadata_values[-1] = metadata_values[-1].strip() # strip trailing newline
322+
with tools._file_context_manager(filename) as fbuf:
323+
# The first 2 lines of the response are headers with metadata
324+
metadata_fields = fbuf.readline().split(',')
325+
metadata_values = fbuf.readline().split(',')
326+
# get the column names so we can set the dtypes
327+
columns = fbuf.readline().split(',')
328+
columns[-1] = columns[-1].strip() # strip trailing newline
329+
# Since the header has so many columns, excel saves blank cols in the
330+
# data below the header lines.
331+
columns = [col for col in columns if col != '']
332+
dtypes = dict.fromkeys(columns, float) # all floats except datevec
333+
dtypes.update({'Year': int, 'Month': int, 'Day': int, 'Hour': int,
334+
'Minute': int, 'Cloud Type': int, 'Fill Flag': int})
335+
data = pd.read_csv(
336+
fbuf, header=None, names=columns, usecols=columns, dtype=dtypes,
337+
delimiter=',', lineterminator='\n') # skip carriage returns \r
338+
339+
metadata_fields[-1] = metadata_fields[-1].strip() # trailing newline
340+
metadata_values[-1] = metadata_values[-1].strip() # trailing newline
324341
metadata = dict(zip(metadata_fields, metadata_values))
325342
# the response is all strings, so set some metadata types to numbers
326343
metadata['Local Time Zone'] = int(metadata['Local Time Zone'])
327344
metadata['Time Zone'] = int(metadata['Time Zone'])
328345
metadata['Latitude'] = float(metadata['Latitude'])
329346
metadata['Longitude'] = float(metadata['Longitude'])
330347
metadata['Elevation'] = int(metadata['Elevation'])
331-
# get the column names so we can set the dtypes
332-
columns = fbuf.readline().split(',')
333-
columns[-1] = columns[-1].strip() # strip trailing newline
334-
# Since the header has so many columns, excel saves blank cols in the
335-
# data below the header lines.
336-
columns = [col for col in columns if col != '']
337-
dtypes = dict.fromkeys(columns, float) # all floats except datevec
338-
dtypes.update(Year=int, Month=int, Day=int, Hour=int, Minute=int)
339-
dtypes['Cloud Type'] = int
340-
dtypes['Fill Flag'] = int
341-
data = pd.read_csv(
342-
fbuf, header=None, names=columns, usecols=columns, dtype=dtypes,
343-
delimiter=',', lineterminator='\n') # skip carriage returns \r
348+
344349
# the response 1st 5 columns are a date vector, convert to datetime
345-
dtidx = pd.to_datetime(
346-
data[['Year', 'Month', 'Day', 'Hour', 'Minute']])
350+
dtidx = pd.to_datetime(data[['Year', 'Month', 'Day', 'Hour', 'Minute']])
347351
# in USA all timezones are integers
348352
tz = 'Etc/GMT%+d' % -metadata['Time Zone']
349353
data.index = pd.DatetimeIndex(dtidx).tz_localize(tz)
@@ -357,43 +361,5 @@ def parse_psm3(fbuf, map_variables=True):
357361
return data, metadata
358362

359363

360-
def read_psm3(filename, map_variables=True):
361-
"""
362-
Read an NSRDB PSM3 weather file (formatted as SAM CSV). The NSRDB
363-
is described in [1]_ and the SAM CSV format is described in [2]_.
364-
365-
.. versionchanged:: 0.9.0
366-
The function now returns a tuple where the first element is a dataframe
367-
and the second element is a dictionary containing metadata. Previous
368-
versions of this function had the return values switched.
369-
370-
Parameters
371-
----------
372-
filename: str
373-
Filename of a file containing data to read.
374-
map_variables: bool, default True
375-
When true, renames columns of the Dataframe to pvlib variable names
376-
where applicable. See variable :const:`VARIABLE_MAP`.
377-
378-
Returns
379-
-------
380-
data : pandas.DataFrame
381-
timeseries data from NREL PSM3
382-
metadata : dict
383-
metadata from NREL PSM3 about the record, see
384-
:func:`pvlib.iotools.parse_psm3` for fields
385-
386-
See Also
387-
--------
388-
pvlib.iotools.parse_psm3, pvlib.iotools.get_psm3
389-
390-
References
391-
----------
392-
.. [1] `NREL National Solar Radiation Database (NSRDB)
393-
<https://nsrdb.nrel.gov/>`_
394-
.. [2] `Standard Time Series Data File Format
395-
<https://web.archive.org/web/20170207203107/https://sam.nrel.gov/sites/default/files/content/documents/pdf/wfcsv.pdf>`_
396-
"""
397-
with open(str(filename), 'r') as fbuf:
398-
content = parse_psm3(fbuf, map_variables)
399-
return content
364+
parse_psm3 = deprecated(since="0.12.1", name="parse_psm3",
365+
alternative="read_psm3")(read_psm3)

‎pvlib/iotools/sodapro.py

Copy file name to clipboardExpand all lines: pvlib/iotools/sodapro.py
+32-60Lines changed: 32 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
import requests
88
import io
99
import warnings
10+
from pvlib import tools
1011

12+
from pvlib._deprecation import deprecated
1113

1214
URL = 'api.soda-solardata.com'
1315

@@ -151,7 +153,7 @@ def get_cams(latitude, longitude, start, end, email, identifier='mcclear',
151153
152154
See Also
153155
--------
154-
pvlib.iotools.read_cams, pvlib.iotools.parse_cams
156+
pvlib.iotools.read_cams
155157
156158
Raises
157159
------
@@ -239,20 +241,22 @@ def get_cams(latitude, longitude, start, end, email, identifier='mcclear',
239241
# Successful requests returns a csv data file
240242
else:
241243
fbuf = io.StringIO(res.content.decode('utf-8'))
242-
data, metadata = parse_cams(fbuf, integrated=integrated, label=label,
243-
map_variables=map_variables)
244+
data, metadata = read_cams(fbuf, integrated=integrated, label=label,
245+
map_variables=map_variables)
244246
return data, metadata
245247

246248

247-
def parse_cams(fbuf, integrated=False, label=None, map_variables=True):
249+
def read_cams(filename, integrated=False, label=None, map_variables=True):
248250
"""
249-
Parse a file-like buffer with data in the format of a CAMS Radiation or
250-
McClear file. The CAMS solar radiation services are described in [1]_.
251+
Read a file or file-like buffer with data in the format of a CAMS
252+
Radiation or McClear file.
253+
254+
The CAMS solar radiation services are described in [1]_.
251255
252256
Parameters
253257
----------
254-
fbuf: file-like object
255-
File-like object containing data to read.
258+
filename: str, path-like, or buffer
259+
Filename or in-memory buffer of a file containing data to read.
256260
integrated: boolean, default False
257261
Whether to return radiation parameters as integrated values (Wh/m^2)
258262
or as average irradiance values (W/m^2) (pvlib preferred units)
@@ -272,23 +276,31 @@ def parse_cams(fbuf, integrated=False, label=None, map_variables=True):
272276
273277
See Also
274278
--------
275-
pvlib.iotools.read_cams, pvlib.iotools.get_cams
279+
pvlib.iotools.get_cams
276280
277281
References
278282
----------
279283
.. [1] `CAMS solar radiation time-series documentation. Climate Data Store.
280284
<https://ads.atmosphere.copernicus.eu/datasets/cams-solar-radiation-timeseries>`_
281285
"""
282286
metadata = {}
283-
# Initial lines starting with # contain metadata
284-
while True:
285-
line = fbuf.readline().rstrip('\n')
286-
if line.startswith('# Observation period'):
287-
# The last line of the metadata section contains the column names
288-
names = line.lstrip('# ').split(';')
289-
break # End of metadata section has been reached
290-
elif ': ' in line:
291-
metadata[line.split(': ')[0].lstrip('# ')] = line.split(': ')[1]
287+
288+
with tools._file_context_manager(filename) as fbuf:
289+
290+
# Initial lines starting with # contain metadata
291+
while True:
292+
line = fbuf.readline().rstrip('\n')
293+
if line.startswith('# Observation period'):
294+
# The last line of the metadata section has the column names
295+
names = line.lstrip('# ').split(';')
296+
break # End of metadata section has been reached
297+
elif ': ' in line:
298+
key = line.split(': ')[0].lstrip('# ')
299+
value = line.split(': ')[1]
300+
metadata[key] = value
301+
302+
data = pd.read_csv(fbuf, sep=';', comment='#', header=None,
303+
names=names)
292304

293305
# Convert latitude, longitude, and altitude values from strings to floats
294306
for k_old in list(metadata.keys()):
@@ -304,8 +316,6 @@ def parse_cams(fbuf, integrated=False, label=None, map_variables=True):
304316
metadata['Summarization (integration) period']]
305317
metadata['time_step'] = time_step
306318

307-
data = pd.read_csv(fbuf, sep=';', comment='#', header=None, names=names)
308-
309319
obs_period = data['Observation period'].str.split('/')
310320

311321
# Set index as the start observation time (left) and localize to UTC
@@ -344,43 +354,5 @@ def parse_cams(fbuf, integrated=False, label=None, map_variables=True):
344354
return data, metadata
345355

346356

347-
def read_cams(filename, integrated=False, label=None, map_variables=True):
348-
"""
349-
Read a CAMS Radiation or McClear file into a pandas DataFrame.
350-
351-
CAMS Radiation and McClear are described in [1]_.
352-
353-
Parameters
354-
----------
355-
filename: str
356-
Filename of a file containing data to read.
357-
integrated: boolean, default False
358-
Whether to return radiation parameters as integrated values (Wh/m^2)
359-
or as average irradiance values (W/m^2) (pvlib preferred units)
360-
label : {'right', 'left}, optional
361-
Which bin edge label to label time-step with. The default is 'left' for
362-
all time steps except for '1M' which has a default of 'right'.
363-
map_variables: bool, default: True
364-
When true, renames columns of the Dataframe to pvlib variable names
365-
where applicable. See variable :const:`VARIABLE_MAP`.
366-
367-
Returns
368-
-------
369-
data: pandas.DataFrame
370-
Timeseries data from CAMS Radiation or McClear.
371-
See :func:`pvlib.iotools.get_cams` for fields.
372-
metadata: dict
373-
Metadata available in the file.
374-
375-
See Also
376-
--------
377-
pvlib.iotools.parse_cams, pvlib.iotools.get_cams
378-
379-
References
380-
----------
381-
.. [1] `CAMS solar radiation time-series documentation. Climate Data Store.
382-
<https://ads.atmosphere.copernicus.eu/datasets/cams-solar-radiation-timeseries>`_
383-
"""
384-
with open(str(filename), 'r') as fbuf:
385-
content = parse_cams(fbuf, integrated, label, map_variables)
386-
return content
357+
parse_cams = deprecated(since="0.12.1", name="parse_cams",
358+
alternative="read_cams")(read_cams)

‎tests/iotools/test_psm3.py

Copy file name to clipboardExpand all lines: tests/iotools/test_psm3.py
+11-2Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
from requests import HTTPError
1717
from io import StringIO
1818

19+
from pvlib._deprecation import pvlibDeprecationWarning
20+
1921

2022
TMY_TEST_DATA = TESTS_DATA_DIR / 'test_psm3_tmy-2017.csv'
2123
YEAR_TEST_DATA = TESTS_DATA_DIR / 'test_psm3_2017.csv'
@@ -130,7 +132,7 @@ def test_get_psm3_tmy_errors(
130132

131133
@pytest.fixture
132134
def io_input(request):
133-
"""file-like object for parse_psm3"""
135+
"""file-like object for read_psm3"""
134136
with MANUAL_TEST_DATA.open() as f:
135137
data = f.read()
136138
obj = StringIO(data)
@@ -139,7 +141,8 @@ def io_input(request):
139141

140142
def test_parse_psm3(io_input):
141143
"""test parse_psm3"""
142-
data, metadata = psm3.parse_psm3(io_input, map_variables=False)
144+
with pytest.warns(pvlibDeprecationWarning, match='Use read_psm3 instead'):
145+
data, metadata = psm3.parse_psm3(io_input, map_variables=False)
143146
expected = pd.read_csv(YEAR_TEST_DATA)
144147
assert_psm3_equal(data, metadata, expected)
145148

@@ -151,6 +154,12 @@ def test_read_psm3():
151154
assert_psm3_equal(data, metadata, expected)
152155

153156

157+
def test_read_psm3_buffer(io_input):
158+
data, metadata = psm3.read_psm3(io_input, map_variables=False)
159+
expected = pd.read_csv(YEAR_TEST_DATA)
160+
assert_psm3_equal(data, metadata, expected)
161+
162+
154163
def test_read_psm3_map_variables():
155164
"""test read_psm3 map_variables=True"""
156165
data, metadata = psm3.read_psm3(MANUAL_TEST_DATA, map_variables=True)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.