ras-commander 0.52.0__py3-none-any.whl → 0.54.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,128 +1,138 @@
1
- from functools import wraps
2
- from pathlib import Path
3
- from typing import Union
4
- import logging
5
- import h5py
6
- import inspect
7
-
8
-
9
- def log_call(func):
10
- @wraps(func)
11
- def wrapper(*args, **kwargs):
12
- logger = logging.getLogger(func.__module__)
13
- logger.info(f"Calling {func.__name__}")
14
- result = func(*args, **kwargs)
15
- logger.info(f"Finished {func.__name__}")
16
- return result
17
- return wrapper
18
-
19
- def standardize_input(file_type: str = 'plan_hdf'):
20
- """
21
- Decorator to standardize input for HDF file operations.
22
-
23
- This decorator processes various input types and converts them to a Path object
24
- pointing to the correct HDF file. It handles the following input types:
25
- - h5py.File objects
26
- - pathlib.Path objects
27
- - Strings (file paths or plan/geom numbers)
28
- - Integers (interpreted as plan/geom numbers)
29
-
30
- The decorator also manages RAS object references and logging.
31
-
32
- Args:
33
- file_type (str): Specifies whether to look for 'plan_hdf' or 'geom_hdf' files.
34
-
35
- Returns:
36
- A decorator that wraps the function to standardize its input to a Path object.
37
- """
38
- def decorator(func):
39
- @wraps(func)
40
- def wrapper(*args, **kwargs):
41
- logger = logging.getLogger(func.__module__)
42
-
43
- # Check if the function expects an hdf_path parameter
44
- sig = inspect.signature(func)
45
- param_names = list(sig.parameters.keys())
46
-
47
- # If first parameter is 'hdf_file', skip path processing
48
- if param_names and param_names[0] == 'hdf_file':
49
- return func(*args, **kwargs)
50
-
51
- # Handle both static method calls and regular function calls
52
- if args and isinstance(args[0], type):
53
- # Static method call, remove the class argument
54
- args = args[1:]
55
-
56
- hdf_input = kwargs.pop('hdf_path', None) or kwargs.pop('hdf_input', None) or (args[0] if args else None)
57
- ras_object = kwargs.pop('ras_object', None) or (args[1] if len(args) > 1 else None)
58
-
59
- # If no hdf_input provided, return the function unmodified
60
- if hdf_input is None:
61
- return func(*args, **kwargs)
62
-
63
- # NEW: If input is already a Path and exists, use it directly regardless of file_type
64
- if isinstance(hdf_input, Path) and hdf_input.is_file():
65
- logger.info(f"Using existing HDF file: {hdf_input}")
66
- new_args = (hdf_input,) + args[1:]
67
- return func(*new_args, **kwargs)
68
-
69
- hdf_path = None
70
-
71
- # If hdf_input is already an h5py.File object, use its filename
72
- if isinstance(hdf_input, h5py.File):
73
- hdf_path = Path(hdf_input.filename)
74
- # Handle Path objects
75
- elif isinstance(hdf_input, Path):
76
- if hdf_input.is_file():
77
- hdf_path = hdf_input
78
- # Handle string inputs
79
- elif isinstance(hdf_input, str):
80
- # Check if it's a file path
81
- if Path(hdf_input).is_file():
82
- hdf_path = Path(hdf_input)
83
- # Check if it's a number (with or without 'p' prefix)
84
- elif hdf_input.isdigit() or (len(hdf_input) == 3 and hdf_input[0] == 'p' and hdf_input[1:].isdigit()):
85
- if ras_object is None:
86
- raise ValueError("RAS object is required when using plan or geom numbers.")
87
- number = hdf_input if hdf_input.isdigit() else hdf_input[1:]
88
-
89
- if file_type == 'plan_hdf':
90
- plan_info = ras_object.plan_df[ras_object.plan_df['plan_number'] == number]
91
- if not plan_info.empty:
92
- hdf_path = Path(plan_info.iloc[0]['HDF_Results_Path'])
93
- elif file_type == 'geom_hdf':
94
- geom_info = ras_object.geom_df[ras_object.geom_df['geom_number'] == number]
95
- if not geom_info.empty:
96
- hdf_path = Path(geom_info.iloc[0]['HDF_Path'])
97
- else:
98
- raise ValueError(f"Invalid file type: {file_type}")
99
- # Handle integer inputs (assuming they're plan or geom numbers)
100
- elif isinstance(hdf_input, int):
101
- if ras_object is None:
102
- raise ValueError("RAS object is required when using plan or geom numbers.")
103
- number = f"{hdf_input:02d}"
104
-
105
- if file_type == 'plan_hdf':
106
- plan_info = ras_object.plan_df[ras_object.plan_df['plan_number'] == number]
107
- if not plan_info.empty:
108
- hdf_path = Path(plan_info.iloc[0]['HDF_Results_Path'])
109
- elif file_type == 'geom_hdf':
110
- geom_info = ras_object.geom_df[ras_object.geom_df['geom_number'] == number]
111
- if not geom_info.empty:
112
- hdf_path = Path(geom_info.iloc[0]['HDF_Path'])
113
- else:
114
- raise ValueError(f"Invalid file type: {file_type}")
115
-
116
- if hdf_path is None or not hdf_path.is_file():
117
- error_msg = f"HDF file not found: {hdf_input}"
118
- logger.error(error_msg)
119
- raise FileNotFoundError(error_msg)
120
-
121
- logger.info(f"Using HDF file: {hdf_path}")
122
-
123
- # Pass all original arguments and keywords, replacing hdf_input with standardized hdf_path
124
- new_args = (hdf_path,) + args[1:]
125
- return func(*new_args, **kwargs)
126
-
127
- return wrapper
1
+ from functools import wraps
2
+ from pathlib import Path
3
+ from typing import Union
4
+ import logging
5
+ import h5py
6
+ import inspect
7
+
8
+
9
+ def log_call(func):
10
+ @wraps(func)
11
+ def wrapper(*args, **kwargs):
12
+ logger = logging.getLogger(func.__module__)
13
+ logger.debug(f"Calling {func.__name__}")
14
+ result = func(*args, **kwargs)
15
+ logger.debug(f"Finished {func.__name__}")
16
+ return result
17
+ return wrapper
18
+
19
+ def standardize_input(file_type: str = 'plan_hdf'):
20
+ """
21
+ Decorator to standardize input for HDF file operations.
22
+
23
+ This decorator processes various input types and converts them to a Path object
24
+ pointing to the correct HDF file. It handles the following input types:
25
+ - h5py.File objects
26
+ - pathlib.Path objects
27
+ - Strings (file paths or plan/geom numbers)
28
+ - Integers (interpreted as plan/geom numbers)
29
+
30
+ The decorator also manages RAS object references and logging.
31
+
32
+ Args:
33
+ file_type (str): Specifies whether to look for 'plan_hdf' or 'geom_hdf' files.
34
+
35
+ Returns:
36
+ A decorator that wraps the function to standardize its input to a Path object.
37
+ """
38
+ def decorator(func):
39
+ @wraps(func)
40
+ def wrapper(*args, **kwargs):
41
+ logger = logging.getLogger(func.__module__)
42
+
43
+ # Check if the function expects an hdf_path parameter
44
+ sig = inspect.signature(func)
45
+ param_names = list(sig.parameters.keys())
46
+
47
+ # If first parameter is 'hdf_file', skip path processing
48
+ if param_names and param_names[0] == 'hdf_file':
49
+ return func(*args, **kwargs)
50
+
51
+ # Handle both static method calls and regular function calls
52
+ if args and isinstance(args[0], type):
53
+ # Static method call, remove the class argument
54
+ args = args[1:]
55
+
56
+ hdf_input = kwargs.pop('hdf_path', None) or kwargs.pop('hdf_input', None) or (args[0] if args else None)
57
+
58
+ # Import ras here to ensure we get the most current instance
59
+ from .RasPrj import ras as ras
60
+ ras_object = kwargs.pop('ras_object', None) or (args[1] if len(args) > 1 else None)
61
+ ras_obj = ras_object or ras
62
+
63
+ # If no hdf_input provided, return the function unmodified
64
+ if hdf_input is None:
65
+ return func(*args, **kwargs)
66
+
67
+ # NEW: If input is already a Path and exists, use it directly regardless of file_type
68
+ if isinstance(hdf_input, Path) and hdf_input.is_file():
69
+ logger.info(f"Using existing HDF file: {hdf_input}")
70
+ new_args = (hdf_input,) + args[1:]
71
+ return func(*new_args, **kwargs)
72
+
73
+ hdf_path = None
74
+
75
+ # If hdf_input is already an h5py.File object, use its filename
76
+ if isinstance(hdf_input, h5py.File):
77
+ hdf_path = Path(hdf_input.filename)
78
+ # Handle Path objects
79
+ elif isinstance(hdf_input, Path):
80
+ if hdf_input.is_file():
81
+ hdf_path = hdf_input
82
+ # Handle string inputs
83
+ elif isinstance(hdf_input, str):
84
+ # Check if it's a file path
85
+ if Path(hdf_input).is_file():
86
+ hdf_path = Path(hdf_input)
87
+ # Check if it's a number (with or without 'p' prefix)
88
+ elif hdf_input.isdigit() or (len(hdf_input) == 3 and hdf_input[0] == 'p' and hdf_input[1:].isdigit()):
89
+ try:
90
+ ras_obj.check_initialized()
91
+ except Exception as e:
92
+ raise ValueError(f"RAS object is not initialized: {str(e)}")
93
+
94
+ number = hdf_input if hdf_input.isdigit() else hdf_input[1:]
95
+
96
+ if file_type == 'plan_hdf':
97
+ plan_info = ras_obj.plan_df[ras_obj.plan_df['plan_number'] == number]
98
+ if not plan_info.empty:
99
+ hdf_path = Path(plan_info.iloc[0]['HDF_Results_Path'])
100
+ elif file_type == 'geom_hdf':
101
+ geom_info = ras_obj.geom_df[ras_obj.geom_df['geom_number'] == number]
102
+ if not geom_info.empty:
103
+ hdf_path = Path(geom_info.iloc[0]['HDF_Path'])
104
+ else:
105
+ raise ValueError(f"Invalid file type: {file_type}")
106
+ # Handle integer inputs (assuming they're plan or geom numbers)
107
+ elif isinstance(hdf_input, int):
108
+ try:
109
+ ras_obj.check_initialized()
110
+ except Exception as e:
111
+ raise ValueError(f"RAS object is not initialized: {str(e)}")
112
+
113
+ number = f"{hdf_input:02d}"
114
+
115
+ if file_type == 'plan_hdf':
116
+ plan_info = ras_obj.plan_df[ras_obj.plan_df['plan_number'] == number]
117
+ if not plan_info.empty:
118
+ hdf_path = Path(plan_info.iloc[0]['HDF_Results_Path'])
119
+ elif file_type == 'geom_hdf':
120
+ geom_info = ras_obj.geom_df[ras_obj.geom_df['geom_number'] == number]
121
+ if not geom_info.empty:
122
+ hdf_path = Path(geom_info.iloc[0]['HDF_Path'])
123
+ else:
124
+ raise ValueError(f"Invalid file type: {file_type}")
125
+
126
+ if hdf_path is None or not hdf_path.is_file():
127
+ error_msg = f"HDF file not found: {hdf_input}"
128
+ logger.error(error_msg)
129
+ raise FileNotFoundError(error_msg)
130
+
131
+ logger.info(f"Using HDF file: {hdf_path}")
132
+
133
+ # Pass all original arguments and keywords, replacing hdf_input with standardized hdf_path
134
+ new_args = (hdf_path,) + args[1:]
135
+ return func(*new_args, **kwargs)
136
+
137
+ return wrapper
128
138
  return decorator
ras_commander/HdfBase.py CHANGED
@@ -158,6 +158,7 @@ class HdfBase:
158
158
 
159
159
  project_folder = hdf_path.parent
160
160
  wkt = None
161
+ proj_file = None # Initialize proj_file variable
161
162
 
162
163
  # Try HDF file
163
164
  try:
@@ -170,6 +171,7 @@ class HdfBase:
170
171
  return wkt
171
172
  except Exception as e:
172
173
  logger.error(f"Error reading projection from HDF file {hdf_path}: {str(e)}")
174
+
173
175
  # Try RASMapper file if no HDF projection
174
176
  if not wkt:
175
177
  try:
@@ -189,16 +191,29 @@ class HdfBase:
189
191
  except Exception as e:
190
192
  logger.error(f"Error reading RASMapper projection file: {str(e)}")
191
193
 
192
- logger.critical(
193
- "No valid projection found. Checked:\n"
194
- f"1. HDF file projection attribute: {hdf_path}\n"
195
- f"2. RASMapper projection file {proj_file} found in RASMapper file, but was invalid\n"
196
- "To fix this:\n"
194
+ # Customize error message based on whether proj_file was found
195
+ if proj_file:
196
+ error_msg = (
197
+ "No valid projection found. Checked:\n"
198
+ f"1. HDF file projection attribute: {hdf_path}\n"
199
+ f"2. RASMapper projection file {proj_file} found in RASMapper file, but was invalid"
200
+ )
201
+ else:
202
+ error_msg = (
203
+ "No valid projection found. Checked:\n"
204
+ f"1. HDF file projection attribute: {hdf_path}\n was checked and no projection attribute found"
205
+ "2. No RASMapper projection file found"
206
+ )
207
+
208
+ error_msg += (
209
+ "\nTo fix this:\n"
197
210
  "1. Open RASMapper\n"
198
211
  "2. Click Map > Set Projection\n"
199
212
  "3. Select an appropriate projection file or coordinate system\n"
200
213
  "4. Save the RASMapper project"
201
214
  )
215
+
216
+ logger.critical(error_msg)
202
217
  return None
203
218
 
204
219
  @staticmethod
@@ -219,7 +234,7 @@ class HdfBase:
219
234
  logger.warning(f"Path {attr_path} not found in HDF file")
220
235
  return {}
221
236
 
222
- return HdfUtils.hdf5_attrs_to_dict(hdf_file[attr_path].attrs)
237
+ return HdfUtils.convert_hdf5_attrs_to_dict(hdf_file[attr_path].attrs)
223
238
  except Exception as e:
224
239
  logger.error(f"Error getting attributes from {attr_path}: {str(e)}")
225
240
  return {}