diff --git a/docs/sphinx/source/whatsnew/v0.13.1.rst b/docs/sphinx/source/whatsnew/v0.13.1.rst index 26a591e534..87fb1ae64f 100644 --- a/docs/sphinx/source/whatsnew/v0.13.1.rst +++ b/docs/sphinx/source/whatsnew/v0.13.1.rst @@ -29,6 +29,8 @@ Enhancements (:pull:`2500`) * :py:func:`pvlib.spectrum.spectral_factor_firstsolar` no longer emits warnings when airmass and precipitable water values fall out of range. (:pull:`2512`) +* Allows reading TMY data from a Path or file-like object in :py:func:`~pvlib.iotools.read_tmy3`. + (:pull:`2544`, :ghuser:`jerluc`) Documentation ~~~~~~~~~~~~~ diff --git a/pvlib/iotools/tmy.py b/pvlib/iotools/tmy.py index 4b6edaeea4..28d20ffc2d 100644 --- a/pvlib/iotools/tmy.py +++ b/pvlib/iotools/tmy.py @@ -4,6 +4,8 @@ import re import pandas as pd +from pvlib.tools import _file_context_manager + # Dictionary mapping TMY3 names to pvlib names VARIABLE_MAP = { 'GHI (W/m^2)': 'ghi', @@ -35,7 +37,7 @@ def read_tmy3(filename, coerce_year=None, map_variables=True, encoding=None): Parameters ---------- - filename : str + filename : str, Path, or file-like object A relative file path or absolute file path. coerce_year : int, optional If supplied, the year of the index will be set to ``coerce_year``, except @@ -186,7 +188,7 @@ def read_tmy3(filename, coerce_year=None, map_variables=True, encoding=None): """ # noqa: E501 head = ['USAF', 'Name', 'State', 'TZ', 'latitude', 'longitude', 'altitude'] - with open(str(filename), 'r', encoding=encoding) as fbuf: + with _file_context_manager(filename, mode="r", encoding=encoding) as fbuf: # header information on the 1st line (0 indexing) firstline = fbuf.readline() # use pandas to read the csv file buffer diff --git a/pvlib/tools.py b/pvlib/tools.py index 63406f4e0d..142e89869b 100644 --- a/pvlib/tools.py +++ b/pvlib/tools.py @@ -562,7 +562,7 @@ def normalize_max2one(a): return res -def _file_context_manager(filename_or_object, mode='r'): +def _file_context_manager(filename_or_object, mode='r', encoding=None): """ Open a filename/path for reading, or pass a file-like object through unchanged. @@ -584,5 +584,5 @@ def _file_context_manager(filename_or_object, mode='r'): context = contextlib.nullcontext(filename_or_object) else: # otherwise, assume a filename or path - context = open(str(filename_or_object), mode=mode) + context = open(str(filename_or_object), mode=mode, encoding=encoding) return context diff --git a/tests/iotools/test_tmy.py b/tests/iotools/test_tmy.py index 63d37ac830..d50609ec47 100644 --- a/tests/iotools/test_tmy.py +++ b/tests/iotools/test_tmy.py @@ -19,6 +19,13 @@ def test_read_tmy3(): tmy.read_tmy3(TMY3_TESTFILE, map_variables=False) +def test_read_tmy3_buffer(): + with open(TMY3_TESTFILE) as f: + data, _ = tmy.read_tmy3(f, map_variables=False) + assert 'GHI source' in data.columns + assert len(data) == 8760 + + def test_read_tmy3_norecolumn(): data, _ = tmy.read_tmy3(TMY3_TESTFILE, map_variables=False) assert 'GHI source' in data.columns