2626import copy
2727import datetime
2828import logging
29+ import warnings
30+
31+ import pandas as pd
2932
3033from climada .entity .exposures import Exposures
3134from climada .entity .impact_funcs import ImpactFuncSet
@@ -46,10 +49,9 @@ class Snapshot:
4649 exposure : Exposures
4750 hazard : Hazard
4851 impfset : ImpactFuncSet
49- date : int | datetime.date | str
50- The date of the Snapshot, it can be an integer representing a year,
51- a datetime object or a string representation of a datetime object
52- with format "YYYY-MM-DD".
52+ date : datetime.date | str | pd.Timestamp
53+ The date of the Snapshot, it can be an string representing a year,
54+ a datetime object or a string representation of a datetime object.
5355 ref_only : bool, default False
5456 Should the `Snapshot` contain deep copies of the Exposures, Hazard and Impfset (False)
5557 or references only (True).
@@ -81,14 +83,22 @@ def __init__(
8183 hazard : Hazard ,
8284 impfset : ImpactFuncSet ,
8385 measure : Measure | None ,
84- date : int | datetime .date | str ,
86+ date : datetime .date | str | pd . Timestamp ,
8587 ref_only : bool = False ,
88+ _from_factory : bool = False ,
8689 ) -> None :
90+ if not _from_factory :
91+ warnings .warn (
92+ "Direct instantiation of 'Snapshot' is discouraged. "
93+ "Use 'Snapshot.from_triplet()' instead." ,
94+ UserWarning ,
95+ stacklevel = 2 ,
96+ )
8797 self ._exposure = exposure if ref_only else copy .deepcopy (exposure )
8898 self ._hazard = hazard if ref_only else copy .deepcopy (hazard )
8999 self ._impfset = impfset if ref_only else copy .deepcopy (impfset )
90- self ._measure = measure if ref_only else copy .deepcopy (impfset )
91- self ._date = self ._convert_to_date (date )
100+ self ._measure = measure if ref_only else copy .deepcopy (measure )
101+ self ._date = self ._convert_to_timestamp (date )
92102
93103 @classmethod
94104 def from_triplet (
@@ -97,7 +107,7 @@ def from_triplet(
97107 exposure : Exposures ,
98108 hazard : Hazard ,
99109 impfset : ImpactFuncSet ,
100- date : int | datetime .date | str ,
110+ date : datetime .date | str | pd . Timestamp ,
101111 ref_only : bool = False ,
102112 ) -> "Snapshot" :
103113 """Create a Snapshot from exposure, hazard and impact functions set
@@ -112,7 +122,7 @@ def from_triplet(
112122 exposure : Exposures
113123 hazard : Hazard
114124 impfset : ImpactFuncSet
115- date : int | datetime.date | str
125+ date : datetime.date | str | pd.Timestamp
116126 ref_only : bool
117127 If true, uses references to the exposure, hazard and impact
118128 function objects. Note that modifying the original objects after
@@ -137,6 +147,7 @@ def from_triplet(
137147 measure = None ,
138148 date = date ,
139149 ref_only = ref_only ,
150+ _from_factory = True ,
140151 )
141152
142153 @property
@@ -160,7 +171,7 @@ def measure(self) -> Measure | None:
160171 return self ._measure
161172
162173 @property
163- def date (self ) -> datetime . date :
174+ def date (self ) -> pd . Timestamp :
164175 """Date of the snapshot."""
165176 return self ._date
166177
@@ -174,24 +185,22 @@ def impact_calc_data(self) -> dict:
174185 }
175186
176187 @staticmethod
177- def _convert_to_date (date_arg ) -> datetime .date :
178- """Convert date argument of type int or str to a datetime.date object."""
179- if isinstance (date_arg , int ):
180- # Assume the integer represents a year
181- return datetime .date (date_arg , 1 , 1 )
188+ def _convert_to_timestamp (date_arg ) -> pd .Timestamp :
189+ """Convert date argument of type str or datetime.date to pandas Timestamp object."""
182190 if isinstance (date_arg , str ):
183191 # Try to parse the string as a date
184192 try :
185- return datetime . datetime . strptime (date_arg , "%Y-%m-%d" ). date ( )
193+ return pd . Timestamp (date_arg )
186194 except ValueError as exc :
187195 raise ValueError ("String must be in the format 'YYYY-MM-DD'" ) from exc
188196 if isinstance (date_arg , datetime .date ):
189- # Already a date object
197+ return pd .Timestamp (date_arg )
198+ if isinstance (date_arg , pd .Timestamp ):
190199 return date_arg
191200
192- raise TypeError ("date_arg must be an int, str, or datetime.date" )
201+ raise TypeError ("date_arg must be an str, datetime.date or pandas.Timestamp " )
193202
194- def apply_measure (self , measure : Measure , ref_only : bool = False ) -> "Snapshot" :
203+ def apply_measure (self , measure : Measure ) -> "Snapshot" :
195204 """Create a new snapshot by applying a Measure object.
196205
197206 This method creates a new `Snapshot` object by applying a measure on
@@ -216,6 +225,7 @@ def apply_measure(self, measure: Measure, ref_only: bool = False) -> "Snapshot":
216225 impfset = impfset ,
217226 date = self .date ,
218227 measure = measure ,
219- ref_only = ref_only ,
228+ ref_only = True , # Avoid unecessary copies of new objects
229+ _from_factory = True ,
220230 )
221231 return snap
0 commit comments