@@ -40,6 +40,13 @@ class PowerPlantType(Enum):
40
40
41
41
42
42
class GeophiresInputParameters :
43
+ """
44
+ .. deprecated:: v3.9.21
45
+ Use :class:`~geophires_x_client.geophires_input_parameters.ImmutableGeophiresInputParameters` instead for
46
+ better performance and guardrails against erroneous usage.
47
+ This class is kept for backwards compatibility, but does not work with GeophiresXClient caching and is more
48
+ susceptible to potential bugs due to its mutability.
49
+ """
43
50
44
51
def __init__ (self , params : Optional [MappingProxyType ] = None , from_file_path : Optional [Path ] = None ):
45
52
"""
@@ -100,15 +107,24 @@ class ImmutableGeophiresInputParameters(GeophiresInputParameters):
100
107
"""
101
108
102
109
params : Mapping [str , Any ] = field (default_factory = lambda : MappingProxyType ({}))
103
- from_file_path : Union [Path , None ] = None
110
+ from_file_path : Union [Path , str , None ] = None
104
111
105
112
# A unique ID for this instance, used for file I/O but not for hashing or equality.
106
113
_instance_id : uuid .UUID = field (default_factory = uuid .uuid4 , init = False , repr = False , compare = False )
107
114
108
115
def __post_init__ (self ):
109
- """Ensures that the parameters dictionary is immutable."""
116
+ """
117
+ Validates input and normalizes field types for immutability and consistency.
118
+ - Ensures from_file_path is a Path object if provided as a string.
119
+ - Ensures the params dictionary is an immutable mapping proxy.
120
+ """
121
+ # Normalize from_file_path to a Path object. object.__setattr__ is required
122
+ # because the dataclass is frozen.
123
+ if self .from_file_path and isinstance (self .from_file_path , str ):
124
+ object .__setattr__ (self , 'from_file_path' , Path (self .from_file_path ))
125
+
126
+ # Ensure params is an immutable proxy
110
127
if not isinstance (self .params , MappingProxyType ):
111
- # object.__setattr__ is required to modify a field in a frozen dataclass
112
128
object .__setattr__ (self , 'params' , MappingProxyType (self .params ))
113
129
114
130
def __hash__ (self ) -> int :
@@ -117,36 +133,38 @@ def __hash__(self) -> int:
117
133
If a base file is used, its content is read and hashed to ensure
118
134
the hash reflects a true snapshot of all inputs.
119
135
"""
120
-
121
136
param_hash = hash (frozenset (self .params .items ()))
122
137
123
- if self .from_file_path is not None and self .from_file_path .exists ():
138
+ file_content_hash = None
139
+ # self.from_file_path is now guaranteed to be a Path object or None
140
+ if self .from_file_path and self .from_file_path .exists ():
124
141
file_content_hash = hash (self .from_file_path .read_bytes ())
125
142
else :
143
+ # Hash the path itself if it's None or doesn't exist.
126
144
file_content_hash = hash (self .from_file_path )
127
145
128
146
return hash ((param_hash , file_content_hash ))
129
147
130
148
def as_file_path (self ) -> Path :
131
149
"""
132
150
Creates a temporary file representation of the parameters on demand.
133
- The resulting file path is cached for efficiency.
151
+ The resulting file path is cached on the instance for efficiency.
134
152
"""
135
153
136
- # Return the cached path if the file has already been generated for this instance.
154
+ # Use hasattr to check for the cached attribute on the frozen instance
137
155
if hasattr (self , '_cached_file_path' ):
138
156
return self ._cached_file_path
139
157
140
158
file_path = Path (tempfile .gettempdir (), f'geophires-input-params_{ self ._instance_id !s} .txt' )
141
159
142
160
with open (file_path , 'w' , encoding = 'UTF-8' ) as f :
143
- if self .from_file_path is not None :
161
+ if self .from_file_path :
144
162
with open (self .from_file_path , encoding = 'UTF-8' ) as base_file :
145
163
f .write (base_file .read ())
146
164
147
165
if self .params :
148
166
# Ensure there is a newline between the base file content and appended params.
149
- if self .from_file_path is not None and f .tell () > 0 :
167
+ if self .from_file_path and f .tell () > 0 :
150
168
f .seek (f .tell () - 1 )
151
169
if f .read (1 ) != '\n ' :
152
170
f .write ('\n ' )
0 commit comments