text: """
  test iotools for PSM3
  """
  
  import os
  from pvlib.iotools import psm3
  from ..conftest import DATA_DIR, RERUNS, RERUNS_DELAY, assert_index_equal
  import numpy as np
  import pandas as pd
  import pytest
  from requests import HTTPError
  from io import StringIO
  import warnings
  from pvlib._deprecation import pvlibDeprecationWarning
  
  TMY_TEST_DATA = DATA_DIR / 'test_psm3_tmy-2017.csv'
  YEAR_TEST_DATA = DATA_DIR / 'test_psm3_2017.csv'
  YEAR_TEST_DATA_5MIN = DATA_DIR / 'test_psm3_2019_5min.csv'
  MANUAL_TEST_DATA = DATA_DIR / 'test_read_psm3.csv'
  LATITUDE, LONGITUDE = 40.5137, -108.5449
  METADATA_FIELDS = [
      'Source', 'Location ID', 'City', 'State', 'Country', 'Latitude',
      'Longitude', 'Time Zone', 'Elevation', 'Local Time Zone',
      'Dew Point Units', 'DHI Units', 'DNI Units', 'GHI Units',
      'Temperature Units', 'Pressure Units', 'Wind Direction Units',
      'Wind Speed Units', 'Surface Albedo Units', 'Version']
  PVLIB_EMAIL = 'pvlib-admin@googlegroups.com'
  
  
  @pytest.fixture(scope="module")
  def nrel_api_key():
      """Supplies pvlib-python's NREL Developer Network API key.
  
      Azure Pipelines CI utilizes a secret variable set to NREL_API_KEY
      to mitigate failures associated with using the default key of
      "DEMO_KEY". A user is capable of using their own key this way if
      desired however the default key should suffice for testing purposes.
      """
      try:
          demo_key = os.environ["NREL_API_KEY"]
      except KeyError:
          warnings.warn(
              "WARNING: NREL API KEY environment variable not set! "
              "Using DEMO_KEY instead. Unexpected failures may occur."
          )
          demo_key = 'DEMO_KEY'
      return demo_key
  
  
  def assert_psm3_equal(data, metadata, expected):
      """check consistency of PSM3 data"""
      # check datevec columns
      assert np.allclose(data.Year, expected.Year)
      assert np.allclose(data.Month, expected.Month)
      assert np.allclose(data.Day, expected.Day)
      assert np.allclose(data.Hour, expected.Hour)
      assert np.allclose(data.Minute, expected.Minute)
      # check data columns
      assert np.allclose(data.GHI, expected.GHI)
      assert np.allclose(data.DNI, expected.DNI)
      assert np.allclose(data.DHI, expected.DHI)
      assert np.allclose(data.Temperature, expected.Temperature)
      assert np.allclose(data.Pressure, expected.Pressure)
      assert np.allclose(data['Dew Point'], expected['Dew Point'])
      assert np.allclose(data['Surface Albedo'], expected['Surface Albedo'])
      assert np.allclose(data['Wind Speed'], expected['Wind Speed'])
      assert np.allclose(data['Wind Direction'], expected['Wind Direction'])
      # check header
      for mf in METADATA_FIELDS:
          assert mf in metadata
      # check timezone
      assert (data.index.tzinfo.zone == 'Etc/GMT%+d' % -metadata['Time Zone'])
  
  
  @pytest.mark.remote_data
  @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
  def test_get_psm3_tmy(nrel_api_key):
      """test get_psm3 with a TMY"""
      data, metadata = psm3.get_psm3(LATITUDE, LONGITUDE, nrel_api_key,
                                     PVLIB_EMAIL, names='tmy-2017',
                                     map_variables=False)
      expected = pd.read_csv(TMY_TEST_DATA)
      assert_psm3_equal(data, metadata, expected)
  
  
  @pytest.mark.remote_data
  @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
  def test_get_psm3_singleyear(nrel_api_key):
      """test get_psm3 with a single year"""
      data, metadata = psm3.get_psm3(LATITUDE, LONGITUDE, nrel_api_key,
                                     PVLIB_EMAIL, names='2017',
                                     map_variables=False, interval=30)
      expected = pd.read_csv(YEAR_TEST_DATA)
      assert_psm3_equal(data, metadata, expected)
  
  
  @pytest.mark.remote_data
  @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
  def test_get_psm3_5min(nrel_api_key):
      """test get_psm3 for 5-minute data"""
      data, metadata = psm3.get_psm3(LATITUDE, LONGITUDE, nrel_api_key,
                                     PVLIB_EMAIL, names='2019', interval=5,
                                     map_variables=False)
      assert len(data) == 525600/5
      first_day = data.loc['2019-01-01']
      expected = pd.read_csv(YEAR_TEST_DATA_5MIN)
      assert_psm3_equal(first_day, metadata, expected)
  
  
  @pytest.mark.remote_data
  @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
  def test_get_psm3_check_leap_day(nrel_api_key):
      data_2012, _ = psm3.get_psm3(LATITUDE, LONGITUDE, nrel_api_key,
                                   PVLIB_EMAIL, names="2012", interval=60,
                                   leap_day=True, map_variables=False)
      assert len(data_2012) == (8760 + 24)
  
  
  @pytest.mark.parametrize('latitude, longitude, api_key, names, interval',
                           [(LATITUDE, LONGITUDE, 'BAD', 'tmy-2017', 60),
                            (51, -5, nrel_api_key, 'tmy-2017', 60),
                            (LATITUDE, LONGITUDE, nrel_api_key, 'bad', 60),
                            (LATITUDE, LONGITUDE, nrel_api_key, '2017', 15),
                            ])
  @pytest.mark.remote_data
  @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
  def test_get_psm3_tmy_errors(
      latitude, longitude, api_key, names, interval
  ):
      """Test get_psm3() for multiple erroneous input scenarios.
  
      These scenarios include:
      * Bad API key -> HTTP 403 forbidden because api_key is rejected
      * Bad latitude/longitude -> Coordinates were not found in the NSRDB.
      * Bad name -> Name is not one of the available options.
      * Bad interval, single year -> Intervals can only be 30 or 60 minutes.
      """
      with pytest.raises(HTTPError) as excinfo:
          psm3.get_psm3(latitude, longitude, api_key, PVLIB_EMAIL,
                        names=names, interval=interval, map_variables=False)
      # ensure the HTTPError caught isn't due to overuse of the API key
      assert "OVER_RATE_LIMIT" not in str(excinfo.value)
  
  
  @pytest.fixture
  def io_input(request):
      """file-like object for parse_psm3"""
      with MANUAL_TEST_DATA.open() as f:
          data = f.read()
      obj = StringIO(data)
      return obj
  
  
  def test_parse_psm3(io_input):
      """test parse_psm3"""
      data, metadata = psm3.parse_psm3(io_input, map_variables=False)
      expected = pd.read_csv(YEAR_TEST_DATA)
      assert_psm3_equal(data, metadata, expected)
  
  
  def test_read_psm3():
      """test read_psm3"""
      data, metadata = psm3.read_psm3(MANUAL_TEST_DATA, map_variables=False)
      expected = pd.read_csv(YEAR_TEST_DATA)
      assert_psm3_equal(data, metadata, expected)
  
  
  def test_read_psm3_map_variables():
      """test read_psm3 map_variables=True"""
      data, metadata = psm3.read_psm3(MANUAL_TEST_DATA, map_variables=True)
      columns_mapped = ['Year', 'Month', 'Day', 'Hour', 'Minute', 'dhi', 'dni',
                        'ghi', 'dhi_clear', 'dni_clear', 'ghi_clear',
                        'Cloud Type', 'Dew Point', 'apparent_zenith',
                        'Fill Flag', 'albedo', 'wind_speed',
                        'precipitable_water', 'wind_direction',
                        'relative_humidity', 'temp_air', 'pressure']
      data, metadata = psm3.read_psm3(MANUAL_TEST_DATA, map_variables=True)
      assert_index_equal(data.columns, pd.Index(columns_mapped))
  
  
  @pytest.mark.remote_data
  @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
  def test_get_psm3_attribute_mapping(nrel_api_key):
      """Test that pvlib names can be passed in as attributes and get correctly
      reverse mapped to PSM3 names"""
      data, meta = psm3.get_psm3(LATITUDE, LONGITUDE, nrel_api_key, PVLIB_EMAIL,
                                 names=2019, interval=60,
                                 attributes=['ghi', 'wind_speed'],
                                 map_variables=True)
      assert 'ghi' in data.columns
      assert 'wind_speed' in data.columns
      assert 'latitude' in meta.keys()
      assert 'longitude' in meta.keys()
      assert 'altitude' in meta.keys()
  
  
  @pytest.mark.remote_data
  @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
  def test_psm3_variable_map_deprecation_warning(nrel_api_key):
      with pytest.warns(pvlibDeprecationWarning, match='names will be renamed'):
          _ = psm3.read_psm3(MANUAL_TEST_DATA)
  