-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Add tests for time conversions in tools package #2341
base: main
Are you sure you want to change the base?
Changes from all commits
9347f12
0638773
c1df9a7
77c0f81
6704d06
dbb1805
6750709
1144106
14715ed
545c196
271fd97
01263c2
60a5d94
9ab2ecf
ddef8d1
4f17f49
a3c3e03
5f59417
c84801f
195efbc
1a5efed
e5af9ae
67e9844
e35eb42
a1a0261
8373ac4
eee6f51
9662c1f
32284ba
01e4cfc
c09a328
4ef4b69
7490792
a5f7646
1382e30
059e35f
f9f07d7
75db2aa
1164c96
5f6ad14
f691bb6
7cfb170
ef5c60f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -12,12 +12,24 @@ Enhancements | |||||||||||||
~~~~~~~~~~~~ | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
Bug Fixes | ||||||||||||||
~~~~~~~~~ | ||||||||||||||
* Ensure proper tz and pytz types in pvlib.location.Location. To ensure that | ||||||||||||||
the time zone in pvlib.location.Location remains internally consistent | ||||||||||||||
if/when the time zone is updated, the tz attribute is now the single source | ||||||||||||||
of time-zone truth, is the single time-zone setter interface, and its getter | ||||||||||||||
returns an IANA string. (:issue:`2340`, :pull:`2341`) | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
Documentation | ||||||||||||||
~~~~~~~~~~~~~ | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
Testing | ||||||||||||||
~~~~~~~ | ||||||||||||||
* Add tests for timezone types in pvlib.location.Location. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
(:issue:`2340`, :pull:`2341`) | ||||||||||||||
* Add tests for time conversions in pvlib.tools. (:issue:`2340`, :pull:`2341`) | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
||||||||||||||
|
||||||||||||||
Requirements | ||||||||||||||
|
@@ -31,6 +43,11 @@ Maintenance | |||||||||||||
* asv 0.4.2 upgraded to asv 0.6.4 to fix CI failure due to pinned older conda. | ||||||||||||||
(:pull:`2352`) | ||||||||||||||
|
||||||||||||||
Breaking Changes | ||||||||||||||
~~~~~~~~~~~~~~~~ | ||||||||||||||
* The pytz attribute in pvlib.location.Location is now read only. pytz time | ||||||||||||||
zones can still be passed to tz in the object initializer and in the tz | ||||||||||||||
setter after object creation. (:issue:`2340`, :pull:`2341`) | ||||||||||||||
Comment on lines
+48
to
+50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Maybe less technical would help. |
||||||||||||||
|
||||||||||||||
Contributors | ||||||||||||||
~~~~~~~~~~~~ | ||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -6,6 +6,7 @@ | |||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
import pathlib | ||||||||||||||||||||||||||||||||||
import datetime | ||||||||||||||||||||||||||||||||||
import zoneinfo | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
import pandas as pd | ||||||||||||||||||||||||||||||||||
import pytz | ||||||||||||||||||||||||||||||||||
|
@@ -18,13 +19,16 @@ | |||||||||||||||||||||||||||||||||
class Location: | ||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||
Location objects are convenient containers for latitude, longitude, | ||||||||||||||||||||||||||||||||||
timezone, and altitude data associated with a particular | ||||||||||||||||||||||||||||||||||
geographic location. You can also assign a name to a location object. | ||||||||||||||||||||||||||||||||||
time zone, 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 two time-zone attributes: | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
* ``tz`` is a IANA timezone string. | ||||||||||||||||||||||||||||||||||
* ``pytz`` is a pytz timezone object. | ||||||||||||||||||||||||||||||||||
* ``tz`` is an IANA time-zone string. | ||||||||||||||||||||||||||||||||||
* ``pytz`` is a pytz-based time-zone object (read only). | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
The read-only ``pytz`` attribute will stay in sync with any changes made | ||||||||||||||||||||||||||||||||||
using ``tz``. | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
Location objects support the print method. | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
|
@@ -38,12 +42,15 @@ 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 : time zone as str, int, float, or datetime.tzinfo, default 'UTC'. | ||||||||||||||||||||||||||||||||||
This value represents as a valid IANA time zone name string. See | ||||||||||||||||||||||||||||||||||
http://en.wikipedia.org/wiki/List_of_tz_database_time_zones for a | ||||||||||||||||||||||||||||||||||
list of valid name strings, any of which may be passed directly here. | ||||||||||||||||||||||||||||||||||
ints and floats must be whole-number hour offsets from UTC, which | ||||||||||||||||||||||||||||||||||
are converted to the IANA-suppored 'Etc/GMT-N' format. (Note the | ||||||||||||||||||||||||||||||||||
limited range of the offset N and its sign-change convention.) | ||||||||||||||||||||||||||||||||||
Time zones from the pytz and zoneinfo packages may also be passed | ||||||||||||||||||||||||||||||||||
directly here, as they are subclasses of datetime.tzinfo. | ||||||||||||||||||||||||||||||||||
Comment on lines
+46
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
altitude : float, optional | ||||||||||||||||||||||||||||||||||
Altitude from sea level in meters. | ||||||||||||||||||||||||||||||||||
|
@@ -54,43 +61,75 @@ class Location: | |||||||||||||||||||||||||||||||||
name : string, optional | ||||||||||||||||||||||||||||||||||
Sets the name attribute of the Location object. | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
Raises | ||||||||||||||||||||||||||||||||||
------ | ||||||||||||||||||||||||||||||||||
ValueError | ||||||||||||||||||||||||||||||||||
when the time-zone ``tz`` input cannot be converted. | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
zoneinfo.ZoneInfoNotFoundError | ||||||||||||||||||||||||||||||||||
when the time zone ``tz`` is not recognizable as an IANA time zone by | ||||||||||||||||||||||||||||||||||
the ``zoneinfo.ZoneInfo`` initializer used for internal time-zone | ||||||||||||||||||||||||||||||||||
representation. | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
See also | ||||||||||||||||||||||||||||||||||
-------- | ||||||||||||||||||||||||||||||||||
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 | ||||||||||||||||||||||||||||||||||
): | ||||||||||||||||||||||||||||||||||
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 | ||||||||||||||||||||||||||||||||||
cwhanse marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||
self.pytz = pytz.FixedOffset(tz*60) | ||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||
raise TypeError('Invalid tz specification') | ||||||||||||||||||||||||||||||||||
self.tz = tz | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
if altitude is None: | ||||||||||||||||||||||||||||||||||
altitude = lookup_altitude(latitude, longitude) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
self.altitude = altitude | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
self.name = name | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
def __repr__(self): | ||||||||||||||||||||||||||||||||||
attrs = ['name', 'latitude', 'longitude', 'altitude', 'tz'] | ||||||||||||||||||||||||||||||||||
# Use None as getattr default in case __repr__ is called during | ||||||||||||||||||||||||||||||||||
# initialization before all attributes have been assigned. | ||||||||||||||||||||||||||||||||||
return ('Location: \n ' + '\n '.join( | ||||||||||||||||||||||||||||||||||
f'{attr}: {getattr(self, attr)}' for attr in attrs)) | ||||||||||||||||||||||||||||||||||
f'{attr}: {getattr(self, attr, None)}' for attr in attrs)) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
@property | ||||||||||||||||||||||||||||||||||
def tz(self): | ||||||||||||||||||||||||||||||||||
"""The location's IANA time-zone string.""" | ||||||||||||||||||||||||||||||||||
return str(self._zoneinfo) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
@tz.setter | ||||||||||||||||||||||||||||||||||
def tz(self, tz_): | ||||||||||||||||||||||||||||||||||
# self._zoneinfo holds single source of time-zone truth as IANA name. | ||||||||||||||||||||||||||||||||||
if isinstance(tz_, str): | ||||||||||||||||||||||||||||||||||
self._zoneinfo = zoneinfo.ZoneInfo(tz_) | ||||||||||||||||||||||||||||||||||
elif isinstance(tz_, int): | ||||||||||||||||||||||||||||||||||
self._zoneinfo = zoneinfo.ZoneInfo(f"Etc/GMT{-tz_:+d}") | ||||||||||||||||||||||||||||||||||
elif isinstance(tz_, float): | ||||||||||||||||||||||||||||||||||
if tz_ % 1 != 0: | ||||||||||||||||||||||||||||||||||
raise TypeError( | ||||||||||||||||||||||||||||||||||
"Floating-point tz has non-zero fractional part: " | ||||||||||||||||||||||||||||||||||
f"{tz_}. Only whole-number offsets are supported." | ||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
self._zoneinfo = zoneinfo.ZoneInfo(f"Etc/GMT{-int(tz_):+d}") | ||||||||||||||||||||||||||||||||||
elif isinstance(tz_, datetime.tzinfo): | ||||||||||||||||||||||||||||||||||
# Includes time zones generated by pytz and zoneinfo packages. | ||||||||||||||||||||||||||||||||||
self._zoneinfo = zoneinfo.ZoneInfo(str(tz_)) | ||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||
raise TypeError( | ||||||||||||||||||||||||||||||||||
f"invalid tz specification: {tz_}, must be an IANA time zone " | ||||||||||||||||||||||||||||||||||
"string, a whole-number int/float UTC offset, or a " | ||||||||||||||||||||||||||||||||||
"datetime.tzinfo object (including subclasses)" | ||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
@property | ||||||||||||||||||||||||||||||||||
def pytz(self): | ||||||||||||||||||||||||||||||||||
"""The location's pytz time zone (read only).""" | ||||||||||||||||||||||||||||||||||
return pytz.timezone(str(self._zoneinfo)) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
@classmethod | ||||||||||||||||||||||||||||||||||
def from_tmy(cls, tmy_metadata, tmy_data=None, **kwargs): | ||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really don't think this is the place to describe how the interface is changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems to me like the "bug fix" here is not to do with what types are allowed, but rather that
Location
now ensures consistency between itstz
andpytz
attributes.