8000 Python and dependency bounds illustration by markcampanelli · Pull Request #2339 · pvlib/pvlib-python · GitHub
[go: up one dir, main page]

Skip to content

Python and dependency bounds illustration #2339

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

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Remove pytz from tools
  • Loading branch information
markcampanelli committed Dec 23, 2024
commit a842ddfc46fa81750127eb05b257971711f94f4d
8 changes: 5 additions & 3 deletions pvlib/iotools/pvgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
import io
import json
from pathlib import Path
from zoneinfo import ZoneInfo

import requests
import numpy as np
import pandas as pd
import pytz

from pvlib.iotools import read_epw, parse_epw

URL = 'https://re.jrc.ec.europa.eu/api/'
Expand Down Expand Up @@ -398,10 +400,10 @@ def _coerce_and_roll_tmy(tmy_data, tz, year):
re-interpreted as zero / UTC.
"""
if tz:
tzname = pytz.timezone(f'Etc/GMT{-tz:+d}')
tzname = ZoneInfo(f'Etc/GMT{-tz:+d}')
else:
tz = 0
tzname = pytz.timezone('UTC')
tzname = ZoneInfo('UTC')
new_index = pd.DatetimeIndex([
timestamp.replace(year=year, tzinfo=tzname)
for timestamp in tmy_data.index],
Expand Down
74 changes: 44 additions & 30 deletions pvlib/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@

# Will Holmgren, University of Arizona, 2014-2016.

import pathlib
import datetime
import pathlib
from zoneinfo import ZoneInfo

import h5py
import pandas as pd
import pytz
import h5py

from pvlib import solarposition, clearsky, atmosphere, irradiance
from pvlib import atmosphere, clearsky, irradiance, solarposition
from pvlib._deprecation import warn_deprecated
from pvlib.tools import _degrees_to_index


Expand All @@ -21,10 +23,12 @@ class Location:
timezone, and altitude data associated with a particular
geographic location. You can also assign a name to a location object.

Location objects have two timezone attributes:
Location objects have one timezone attribute:

* ``tz`` is a IANA-compatible standard-library zoneinfo.ZoneInfo.

* ``tz`` is a IANA timezone string.
* ``pytz`` is a pytz timezone object.
Thus, the passed timezone must be representable by one of the values in
zoneinfo.available_timezones().

Location objects support the print method.

Expand All @@ -38,12 +42,12 @@ class Location:
Positive is east of the prime meridian.
Use decimal degrees notation.

tz : str, int, float, or pytz.timezone, default 'UTC'.
See
http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
for a list of valid time zones.
pytz.timezone objects will be converted to strings.
ints and floats must be in hours from UTC.
tz : str, int, float, zoneinfo.ZoneInfo, datetime.timez 8000 one, or pytz timezone (deprecated), default 'UTC'.
See http://en.wikipedia.org/wiki/List_of_tz_database_time_zones for a
list of valid time zone strings, or use the function
zoneinfo.available_timezones().
ints and floats must be in hours N from UTC, and are converted to the
Etc/GMT+N or Etc/GMT-N format depending on the sign of N.

altitude : float, optional
Altitude from sea level in meters.
Expand All @@ -59,33 +63,43 @@ class Location:
pvlib.pvsystem.PVSystem
"""

def __init__(self, latitude, longitude, tz='UTC', altitude=None,
name=None):
def __init__(
self, latitude, longitude, tz='UTC', altitude=None, name=None
):

if name is None:
name = ""

self.name = name

self.latitude = latitude
self.longitude = longitude

if isinstance(tz, str):
self.tz = tz
self.pytz = pytz.timezone(tz)
elif isinstance(tz, datetime.timezone):
self.tz = 'UTC'
self.pytz = pytz.UTC
elif isinstance(tz, datetime.tzinfo):
self.tz = tz.zone
self.pytz = tz
elif isinstance(tz, (int, float)):
self.tz = tz
self.pytz = pytz.FixedOffset(tz*60)
else:
raise TypeError('Invalid tz specification')

if altitude is None:
altitude = lookup_altitude(latitude, longitude)

self.altitude = altitude

self.name = name
if isinstance(tz, str):
self.tz = ZoneInfo(tz)
elif isinstance(tz, int):
self.tz = ZoneInfo(f"Etc/GMT{-tz:+d}")
elif isinstance(tz, float):
self.tz = ZoneInfo(f"Etc/GMT{int(-tz):+d}")
elif isinstance(tz, ZoneInfo):
self.tz = tz
elif isinstance(tz, datetime.timezone):
self.tz = ZoneInfo(str(tz))
elif isinstance(tz, pytz.BaseTzInfo):
warn_deprecated(
"0.11.3",
message='pytz timezones are deprecated',
alternative='use zoneinfo.ZoneInfo from the standard library',
obj_type='function argument type',
)
self.tz = ZoneInfo(tz.zone)
else:
raise TypeError(f'Invalid tz specification: {tz}')

def __repr__(self):
attrs = ['name', 'latitude', 'longitude', 'altitude', 'tz']
Expand Down
1 change: 0 additions & 1 deletion pvlib/temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import numpy as np
import pandas as pd
from pvlib.tools import sind
from pvlib._deprecation import warn_deprecated
from pvlib.tools import _get_sample_intervals
import scipy
import scipy.constants
Expand Down
3 changes: 1 addition & 2 deletions pvlib/tests/iotools/test_midc.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import pandas as pd
import pytest
import pytz

from pvlib.iotools import midc
from ..conftest import DATA_DIR, RERUNS, RERUNS_DELAY
Expand Down Expand Up @@ -43,7 +42,7 @@ def test_midc__format_index_tz_conversion():
data = pd.read_csv(MIDC_TESTFILE)
data = data.rename(columns={'MST': 'PST'})
data = midc._format_index(data)
assert data.index[0].tz == pytz.timezone('Etc/GMT+8')
assert str(data.index[0].tz) == 'Etc/GMT+8'


def test_midc__format_index_raw():
Expand Down
4 changes: 2 additions & 2 deletions pvlib/tests/test_clearsky.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from collections import OrderedDict
from zoneinfo import ZoneInfo

import numpy as np
from numpy import nan
import pandas as pd
import pytz
from scipy.linalg import hankel

import pytest
Expand Down Expand Up @@ -758,7 +758,7 @@ def test_bird():
times = pd.date_range(start='1/1/2015 0:00', end='12/31/2015 23:00',
freq='h')
tz = -7 # test timezone
gmt_tz = pytz.timezone('Etc/GMT%+d' % -(tz))
gmt_tz = ZoneInfo(f"Etc/GMT{-tz:+}")
times = times.tz_localize(gmt_tz) # set timezone
times_utc = times.tz_convert('UTC')
# match test data from BIRD_08_16_2012.xls
Expand Down
19 changes: 9 additions & 10 deletions pvlib/tests/test_location.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import datetime
from unittest.mock import ANY
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError

import numpy as np
from numpy import nan
import pandas as pd
from .conftest import assert_frame_equal, assert_index_equal

import pytest

import pytz
from pytz.exceptions import UnknownTimeZoneError

import pvlib
from pvlib import location
Expand All @@ -28,15 +27,15 @@ def test_location_all():


@pytest.mark.parametrize('tz', [
pytz.timezone('US/Arizona'), 'America/Phoenix', -7, -7.0,
datetime.timezone.utc
pytz.timezone('US/Arizona'), ZoneInfo('US/Arizona'), 'America/Phoenix',
-7, -7.0, datetime.timezone.utc
])
def test_location_tz(tz):
Location(32.2, -111, tz)


def test_location_invalid_tz():
with pytest.raises(UnknownTimeZoneError):
with pytest.raises(ZoneInfoNotFoundError):
Location(32.2, -111, 'invalid')


Expand All @@ -58,8 +57,8 @@ def test_location_print_all():
assert tus.__str__() == expected_str


def test_location_print_pytz():
tus = Location(32.2, -111, pytz.timezone('US/Arizona'), 700, 'Tucson')
def test_location_print_zoneinfo():
tus = Location(32.2, -111, ZoneInfo('US/Arizona'), 700, 'Tucson')
expected_str = '\n'.join([
'Location: ',
' name: Tucson',
Expand Down Expand Up @@ -215,7 +214,7 @@ def test_from_tmy_3():
from pvlib.iotools import read_tmy3
data, meta = read_tmy3(TMY3_TESTFILE, map_variables=True)
loc = Location.from_tmy(meta, data)
assert loc.name is not None
assert loc.name != ""
assert loc.altitude != 0
assert loc.tz != 'UTC'
assert_frame_equal(loc.weather, data)
Expand All @@ -226,7 +225,7 @@ def test_from_tmy_2():
from pvlib.iotools import read_tmy2
data, meta = read_tmy2(TMY2_TESTFILE)
loc = Location.from_tmy(meta, data)
assert loc.name is not None
assert loc.name != ""
assert loc.altitude != 0
assert loc.tz != 'UTC'
assert_frame_equal(loc.weather, data)
Expand All @@ -237,7 +236,7 @@ def test_from_epw():
from pvlib.iotools import read_epw
data, meta = read_epw(epw_testfile)
loc = Location.from_epw(meta, data)
assert loc.name is not None
assert loc.name != ""
assert loc.altitude != 0
assert loc.tz != 'UTC'
assert_frame_equal(loc.weather, data)
Expand Down
2 changes: 0 additions & 2 deletions pvlib/tests/test_solarposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,15 +344,13 @@ def test_pyephem_physical_dst(expected_solpos, golden):

@requires_ephem
def test_calc_time():
import pytz
import math
# validation from USNO solar position calculator online

epoch = datetime.datetime(1970, 1, 1)
epoch_dt = pytz.utc.localize(epoch)

loc = tus
loc.pressure = 0
actual_time = pytz.timezone(loc.tz).localize(
datetime.datetime(2014, 10, 10, 8, 30))
lb = pytz.timezone(loc.tz).localize(datetime.datetime(2014, 10, 10, tol))
Expand Down
4 changes: 1 addition & 3 deletions pvlib/tests/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,7 @@ def test_localize_to_utc(input, expected):
),
(
{
"time": datetime(
1974, 6, 22, 23, 30, 15, tzinfo=ZoneInfo("UTC")
)
"time": datetime(1974, 6, 22, 23, 30, 15)
},
27201.47934027778,
),
Expand Down
24 changes: 13 additions & 11 deletions pvlib/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
"""

import datetime as dt
import warnings
import zoneinfo

import numpy as np
import pandas as pd
import pytz
import warnings


def cosd(angle):
Expand Down Expand Up @@ -133,13 +134,14 @@ def localize_to_utc(time, location):
"""
if isinstance(time, dt.datetime):
if time.tzinfo is None:
time = pytz.timezone(location.tz).localize(time)
time_utc = time.astimezone(pytz.utc)
time = time.replace(tzinfo=location.tz)

time_utc = time.astimezone(zoneinfo.ZoneInfo("UTC"))
else:
try:
time_utc = time.tz_convert('UTC')
except TypeError:
time_utc = time.tz_localize(location.tz).tz_convert('UTC')
time_utc = time.tz_localize(str(location.tz)).tz_convert('UTC')

return time_utc

Expand All @@ -160,11 +162,11 @@ def datetime_to_djd(time):
"""

if time.tzinfo is None:
time_utc = pytz.utc.localize(time)
time_utc = time.replace(tzinfo=zoneinfo.ZoneInfo("UTC"))
else:
time_utc = time.astimezone(pytz.utc)
time_utc = time.astimezone(zoneinfo.ZoneInfo("UTC"))

djd_start = pytz.utc.localize(dt.datetime(1899, 12, 31, 12))
djd_start = dt.datetime(1899, 12, 31, 12, tzinfo=zoneinfo.ZoneInfo("UTC"))
djd = (time_utc - djd_start).total_seconds() * 1.0/(60 * 60 * 24)

return djd
Expand All @@ -187,10 +189,10 @@ def djd_to_datetime(djd, tz='UTC'):
The resultant datetime localized to tz
"""

djd_start = pytz.utc.localize(dt.datetime(1899, 12, 31, 12))

djd_start = dt.datetime(1899, 12, 31, 12, tzinfo=zoneinfo.ZoneInfo("UTC"))
utc_time = djd_start + dt.timedelta(days=djd)
return utc_time.astimezone(pytz.timezone(tz))

return utc_time.astimezone(zoneinfo.ZoneInfo(tz))


def _pandas_to_doy(pd_object):
Expand Down
0