ras-commander 0.64.0__py3-none-any.whl → 0.66.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.
- ras_commander/RasPlan.py +1487 -1471
- ras_commander/RasPrj.py +263 -126
- ras_commander/RasUtils.py +22 -3
- ras_commander/__init__.py +1 -1
- {ras_commander-0.64.0.dist-info → ras_commander-0.66.0.dist-info}/METADATA +1 -1
- {ras_commander-0.64.0.dist-info → ras_commander-0.66.0.dist-info}/RECORD +9 -9
- {ras_commander-0.64.0.dist-info → ras_commander-0.66.0.dist-info}/LICENSE +0 -0
- {ras_commander-0.64.0.dist-info → ras_commander-0.66.0.dist-info}/WHEEL +0 -0
- {ras_commander-0.64.0.dist-info → ras_commander-0.66.0.dist-info}/top_level.txt +0 -0
ras_commander/RasPrj.py
CHANGED
@@ -160,93 +160,96 @@ class RasPrj:
|
|
160
160
|
Load project data from the HEC-RAS project file.
|
161
161
|
|
162
162
|
This method initializes DataFrames for plan, flow, unsteady, and geometry entries
|
163
|
-
|
164
|
-
Also extracts unsteady_number and geometry_number from plan files and adds them to plan_df.
|
163
|
+
and ensures all required columns are present with appropriate paths.
|
165
164
|
"""
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
165
|
+
try:
|
166
|
+
# Load data frames
|
167
|
+
self.unsteady_df = self._get_prj_entries('Unsteady')
|
168
|
+
self.plan_df = self._get_prj_entries('Plan')
|
169
|
+
self.flow_df = self._get_prj_entries('Flow')
|
170
|
+
self.geom_df = self.get_geom_entries()
|
171
|
+
|
172
|
+
# Ensure required columns exist
|
173
|
+
self._ensure_required_columns()
|
174
|
+
|
175
|
+
# Set paths for geometry and flow files
|
176
|
+
self._set_file_paths()
|
177
|
+
|
178
|
+
except Exception as e:
|
179
|
+
logger.error(f"Error loading project data: {e}")
|
180
|
+
raise
|
181
|
+
|
182
|
+
def _ensure_required_columns(self):
|
183
|
+
"""Ensure all required columns exist in plan_df."""
|
184
|
+
required_columns = [
|
185
|
+
'plan_number', 'unsteady_number', 'geometry_number',
|
186
|
+
'Geom File', 'Geom Path', 'Flow File', 'Flow Path', 'full_path'
|
187
|
+
]
|
171
188
|
|
172
|
-
|
173
|
-
|
189
|
+
for col in required_columns:
|
190
|
+
if col not in self.plan_df.columns:
|
191
|
+
self.plan_df[col] = None
|
174
192
|
|
175
|
-
|
193
|
+
if not self.plan_df['full_path'].any():
|
194
|
+
self.plan_df['full_path'] = self.plan_df['plan_number'].apply(
|
195
|
+
lambda x: str(self.project_folder / f"{self.project_name}.p{x}")
|
196
|
+
)
|
197
|
+
|
198
|
+
def _set_file_paths(self):
|
199
|
+
"""Set geometry and flow paths in plan_df."""
|
176
200
|
for idx, row in self.plan_df.iterrows():
|
177
201
|
try:
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
logger.info(f"Plan {row['plan_number']} uses geometry file {geom_number}")
|
202
|
+
self._set_geom_path(idx, row)
|
203
|
+
self._set_flow_path(idx, row)
|
204
|
+
|
205
|
+
if not self.suppress_logging:
|
206
|
+
logger.info(f"Plan {row['plan_number']} paths set up")
|
184
207
|
except Exception as e:
|
185
208
|
logger.error(f"Error processing plan file {row['plan_number']}: {e}")
|
186
209
|
|
187
|
-
def
|
188
|
-
"""
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
Parameters:
|
193
|
-
-----------
|
194
|
-
plan_file_path : str or Path
|
195
|
-
Path to the plan file.
|
196
|
-
|
197
|
-
Returns:
|
198
|
-
--------
|
199
|
-
tuple: (str, str)
|
200
|
-
A tuple containing (geometry_number, full_hdf_path) or (None, None) if not found.
|
201
|
-
geometry_number is the number after 'g' in the Geom File value
|
202
|
-
full_hdf_path is the path to the geometry HDF file
|
203
|
-
"""
|
204
|
-
content, encoding = read_file_with_fallback_encoding(plan_file_path)
|
205
|
-
|
206
|
-
if content is None:
|
207
|
-
return None, None
|
208
|
-
|
209
|
-
try:
|
210
|
-
match = re.search(r'Geom File=g(\d+)', content)
|
211
|
-
if match:
|
212
|
-
geom_number = match.group(1) # This gets just the number after 'g'
|
213
|
-
geom_file = f"g{geom_number}"
|
214
|
-
geom_hdf_path = self.project_folder / f"{self.project_name}.{geom_file}.hdf"
|
215
|
-
if geom_hdf_path.exists():
|
216
|
-
return geom_number, str(geom_hdf_path)
|
217
|
-
except Exception as e:
|
218
|
-
logger.error(f"Error extracting geometry number from {plan_file_path}: {e}")
|
219
|
-
|
220
|
-
return None, None
|
210
|
+
def _set_geom_path(self, idx: int, row: pd.Series):
|
211
|
+
"""Set geometry path for a plan entry."""
|
212
|
+
if pd.notna(row['Geom File']):
|
213
|
+
geom_path = self.project_folder / f"{self.project_name}.g{row['Geom File']}"
|
214
|
+
self.plan_df.at[idx, 'Geom Path'] = str(geom_path)
|
221
215
|
|
222
|
-
def
|
216
|
+
def _set_flow_path(self, idx: int, row: pd.Series):
|
217
|
+
"""Set flow path for a plan entry."""
|
218
|
+
if pd.notna(row['Flow File']):
|
219
|
+
prefix = 'u' if pd.notna(row['unsteady_number']) else 'f'
|
220
|
+
flow_path = self.project_folder / f"{self.project_name}.{prefix}{row['Flow File']}"
|
221
|
+
self.plan_df.at[idx, 'Flow Path'] = str(flow_path)
|
222
|
+
|
223
|
+
def _get_geom_file_for_plan(self, plan_number):
|
223
224
|
"""
|
224
|
-
|
225
|
+
Get the geometry file path for a given plan number.
|
225
226
|
|
226
|
-
|
227
|
-
|
228
|
-
plan_file_path : str or Path
|
229
|
-
Path to the plan file.
|
227
|
+
Args:
|
228
|
+
plan_number (str): The plan number to find the geometry file for.
|
230
229
|
|
231
230
|
Returns:
|
232
|
-
|
233
|
-
str or None
|
234
|
-
The Flow File value or None if not found.
|
231
|
+
str: The full path to the geometry HDF file, or None if not found.
|
235
232
|
"""
|
233
|
+
plan_file_path = self.project_folder / f"{self.project_name}.p{plan_number}"
|
236
234
|
content, encoding = read_file_with_fallback_encoding(plan_file_path)
|
237
235
|
|
238
236
|
if content is None:
|
239
237
|
return None
|
240
238
|
|
241
239
|
try:
|
242
|
-
|
243
|
-
|
244
|
-
|
240
|
+
for line in content.splitlines():
|
241
|
+
if line.startswith("Geom File="):
|
242
|
+
geom_file = line.strip().split('=')[1]
|
243
|
+
geom_hdf_path = self.project_folder / f"{self.project_name}.{geom_file}.hdf"
|
244
|
+
if geom_hdf_path.exists():
|
245
|
+
return str(geom_hdf_path)
|
246
|
+
else:
|
247
|
+
return None
|
245
248
|
except Exception as e:
|
246
|
-
logger.error(f"Error
|
247
|
-
|
249
|
+
logger.error(f"Error reading plan file for geometry: {e}")
|
248
250
|
return None
|
249
251
|
|
252
|
+
|
250
253
|
@staticmethod
|
251
254
|
@log_call
|
252
255
|
def get_plan_value(
|
@@ -431,80 +434,106 @@ class RasPrj:
|
|
431
434
|
|
432
435
|
Returns:
|
433
436
|
pd.DataFrame: A DataFrame containing the extracted entries.
|
437
|
+
|
438
|
+
Raises:
|
439
|
+
Exception: If there's an error reading or processing the project file.
|
434
440
|
"""
|
435
441
|
entries = []
|
436
442
|
pattern = re.compile(rf"{entry_type} File=(\w+)")
|
437
443
|
|
438
444
|
try:
|
439
|
-
with open(self.prj_file, 'r') as file:
|
445
|
+
with open(self.prj_file, 'r', encoding='utf-8') as file:
|
440
446
|
for line in file:
|
441
447
|
match = pattern.match(line.strip())
|
442
448
|
if match:
|
443
449
|
file_name = match.group(1)
|
444
450
|
full_path = str(self.project_folder / f"{self.project_name}.{file_name}")
|
445
|
-
entry_number = file_name[1:]
|
451
|
+
entry_number = file_name[1:]
|
446
452
|
|
447
453
|
entry = {
|
448
454
|
f'{entry_type.lower()}_number': entry_number,
|
449
455
|
'full_path': full_path
|
450
456
|
}
|
451
457
|
|
458
|
+
# Handle Unsteady entries
|
452
459
|
if entry_type == 'Unsteady':
|
453
|
-
entry
|
454
|
-
unsteady_info = self._parse_unsteady_file(Path(full_path))
|
455
|
-
entry.update(unsteady_info)
|
460
|
+
entry.update(self._process_unsteady_entry(entry_number, full_path))
|
456
461
|
else:
|
457
|
-
entry.update(
|
458
|
-
'unsteady_number': None,
|
459
|
-
'geometry_number': None,
|
460
|
-
'Short Identifier': None,
|
461
|
-
'Simulation Date': None
|
462
|
-
})
|
462
|
+
entry.update(self._process_default_entry())
|
463
463
|
|
464
|
+
# Handle Plan entries
|
464
465
|
if entry_type == 'Plan':
|
465
|
-
|
466
|
-
if plan_info:
|
467
|
-
# Handle Flow File (unsteady) number
|
468
|
-
flow_file = plan_info.get('Flow File')
|
469
|
-
if flow_file and flow_file.startswith('u'):
|
470
|
-
entry['unsteady_number'] = flow_file[1:]
|
471
|
-
else:
|
472
|
-
entry['unsteady_number'] = flow_file
|
473
|
-
|
474
|
-
# Handle Geom File number
|
475
|
-
geom_file = plan_info.get('Geom File')
|
476
|
-
if geom_file and geom_file.startswith('g'):
|
477
|
-
entry['geometry_number'] = geom_file[1:]
|
478
|
-
else:
|
479
|
-
entry['geometry_number'] = geom_file
|
480
|
-
|
481
|
-
entry['Short Identifier'] = plan_info.get('Short Identifier')
|
482
|
-
entry['Simulation Date'] = plan_info.get('Simulation Date')
|
483
|
-
|
484
|
-
# Update remaining fields
|
485
|
-
for key, value in plan_info.items():
|
486
|
-
if key not in ['unsteady_number', 'geometry_number', 'Short Identifier',
|
487
|
-
'Simulation Date', 'Flow File', 'Geom File']:
|
488
|
-
entry[key] = value
|
466
|
+
entry.update(self._process_plan_entry(entry_number, full_path))
|
489
467
|
|
490
|
-
# Add HDF results path
|
491
|
-
hdf_results_path = self.project_folder / f"{self.project_name}.p{entry_number}.hdf"
|
492
|
-
entry['HDF_Results_Path'] = str(hdf_results_path) if hdf_results_path.exists() else None
|
493
|
-
|
494
468
|
entries.append(entry)
|
495
|
-
|
496
|
-
df = pd.DataFrame(entries)
|
497
|
-
|
498
|
-
if not df.empty and entry_type == 'Plan':
|
499
|
-
first_cols = [f'{entry_type.lower()}_number', 'unsteady_number', 'geometry_number',
|
500
|
-
'Short Identifier', 'Simulation Date']
|
501
|
-
other_cols = [col for col in df.columns if col not in first_cols]
|
502
|
-
df = df[first_cols + other_cols]
|
503
469
|
|
504
|
-
|
470
|
+
df = pd.DataFrame(entries)
|
471
|
+
return self._format_dataframe(df, entry_type)
|
472
|
+
|
505
473
|
except Exception as e:
|
474
|
+
logger.error(f"Error in _get_prj_entries for {entry_type}: {e}")
|
506
475
|
raise
|
507
476
|
|
477
|
+
def _process_unsteady_entry(self, entry_number: str, full_path: str) -> dict:
|
478
|
+
"""Process unsteady entry data."""
|
479
|
+
entry = {'unsteady_number': entry_number}
|
480
|
+
unsteady_info = self._parse_unsteady_file(Path(full_path))
|
481
|
+
entry.update(unsteady_info)
|
482
|
+
return entry
|
483
|
+
|
484
|
+
def _process_default_entry(self) -> dict:
|
485
|
+
"""Process default entry data."""
|
486
|
+
return {
|
487
|
+
'unsteady_number': None,
|
488
|
+
'geometry_number': None
|
489
|
+
}
|
490
|
+
|
491
|
+
def _process_plan_entry(self, entry_number: str, full_path: str) -> dict:
|
492
|
+
"""Process plan entry data."""
|
493
|
+
entry = {}
|
494
|
+
plan_info = self._parse_plan_file(Path(full_path))
|
495
|
+
|
496
|
+
if plan_info:
|
497
|
+
entry.update(self._process_flow_file(plan_info))
|
498
|
+
entry.update(self._process_geom_file(plan_info))
|
499
|
+
|
500
|
+
# Add remaining plan info
|
501
|
+
for key, value in plan_info.items():
|
502
|
+
if key not in ['Flow File', 'Geom File']:
|
503
|
+
entry[key] = value
|
504
|
+
|
505
|
+
# Add HDF results path
|
506
|
+
hdf_results_path = self.project_folder / f"{self.project_name}.p{entry_number}.hdf"
|
507
|
+
entry['HDF_Results_Path'] = str(hdf_results_path) if hdf_results_path.exists() else None
|
508
|
+
|
509
|
+
return entry
|
510
|
+
|
511
|
+
def _process_flow_file(self, plan_info: dict) -> dict:
|
512
|
+
"""Process flow file information from plan info."""
|
513
|
+
flow_file = plan_info.get('Flow File')
|
514
|
+
if flow_file and flow_file.startswith('u'):
|
515
|
+
return {
|
516
|
+
'unsteady_number': flow_file[1:],
|
517
|
+
'Flow File': flow_file[1:]
|
518
|
+
}
|
519
|
+
return {
|
520
|
+
'unsteady_number': None,
|
521
|
+
'Flow File': flow_file[1:] if flow_file and flow_file.startswith('f') else None
|
522
|
+
}
|
523
|
+
|
524
|
+
def _process_geom_file(self, plan_info: dict) -> dict:
|
525
|
+
"""Process geometry file information from plan info."""
|
526
|
+
geom_file = plan_info.get('Geom File')
|
527
|
+
if geom_file and geom_file.startswith('g'):
|
528
|
+
return {
|
529
|
+
'geometry_number': geom_file[1:],
|
530
|
+
'Geom File': geom_file[1:]
|
531
|
+
}
|
532
|
+
return {
|
533
|
+
'geometry_number': None,
|
534
|
+
'Geom File': None
|
535
|
+
}
|
536
|
+
|
508
537
|
def _parse_unsteady_file(self, unsteady_file_path):
|
509
538
|
"""
|
510
539
|
Parse an unsteady flow file and extract critical information.
|
@@ -895,27 +924,135 @@ class RasPrj:
|
|
895
924
|
return bc_info, unparsed_lines
|
896
925
|
|
897
926
|
@log_call
|
898
|
-
def
|
927
|
+
def _format_dataframe(self, df, entry_type):
|
899
928
|
"""
|
900
|
-
|
929
|
+
Format the DataFrame according to the desired column structure.
|
930
|
+
|
931
|
+
Args:
|
932
|
+
df (pd.DataFrame): The DataFrame to format.
|
933
|
+
entry_type (str): The type of entry (e.g., 'Plan', 'Flow', 'Unsteady', 'Geom').
|
901
934
|
|
902
935
|
Returns:
|
903
|
-
|
904
|
-
|
905
|
-
|
936
|
+
pd.DataFrame: The formatted DataFrame.
|
937
|
+
"""
|
938
|
+
if df.empty:
|
939
|
+
return df
|
906
940
|
|
907
|
-
|
908
|
-
|
909
|
-
|
941
|
+
if entry_type == 'Plan':
|
942
|
+
# Define column groups
|
943
|
+
first_cols = ['plan_number', 'unsteady_number', 'geometry_number']
|
944
|
+
plan_key_cols = [
|
945
|
+
'Plan Title', 'Program Version', 'Short Identifier', 'Simulation Date',
|
946
|
+
'Computation Interval', 'Mapping Interval', 'Run HTab', 'Run UNet',
|
947
|
+
'Run Sediment', 'Run PostProcess', 'Run WQNet', 'UNET Use Existing IB Tables',
|
948
|
+
'HDF_Results_Path', 'UNET 1D Methodology'
|
949
|
+
]
|
950
|
+
file_path_cols = ['Geom File', 'Geom Path', 'Flow File', 'Flow Path']
|
951
|
+
|
952
|
+
# Build column list
|
953
|
+
all_cols = first_cols.copy()
|
954
|
+
all_cols.extend([col for col in plan_key_cols if col in df.columns])
|
955
|
+
all_cols.extend([col for col in df.columns if col not in all_cols + file_path_cols + ['full_path']])
|
956
|
+
all_cols.extend(file_path_cols)
|
957
|
+
|
958
|
+
# Rename and fill missing columns
|
959
|
+
df = df.rename(columns={f'{entry_type.lower()}_number': 'plan_number'})
|
960
|
+
for col in all_cols:
|
961
|
+
if col not in df.columns:
|
962
|
+
df[col] = None
|
963
|
+
|
964
|
+
# Add full_path if present
|
965
|
+
if 'full_path' in df.columns:
|
966
|
+
all_cols.append('full_path')
|
967
|
+
|
968
|
+
return df[[col for col in all_cols if col in df.columns]]
|
969
|
+
|
970
|
+
return df
|
971
|
+
|
972
|
+
@log_call
|
973
|
+
def _get_prj_entries(self, entry_type):
|
910
974
|
"""
|
911
|
-
|
975
|
+
Extract entries of a specific type from the HEC-RAS project file.
|
976
|
+
"""
|
977
|
+
entries = []
|
978
|
+
pattern = re.compile(rf"{entry_type} File=(\w+)")
|
979
|
+
|
980
|
+
try:
|
981
|
+
with open(self.prj_file, 'r') as file:
|
982
|
+
for line in file:
|
983
|
+
match = pattern.match(line.strip())
|
984
|
+
if match:
|
985
|
+
file_name = match.group(1)
|
986
|
+
full_path = str(self.project_folder / f"{self.project_name}.{file_name}")
|
987
|
+
entry = self._create_entry(entry_type, file_name, full_path)
|
988
|
+
entries.append(entry)
|
912
989
|
|
913
|
-
|
914
|
-
unsteady_plans = self.plan_df[self.plan_df['unsteady_number'].notna()].copy()
|
990
|
+
return self._format_dataframe(pd.DataFrame(entries), entry_type)
|
915
991
|
|
916
|
-
|
992
|
+
except Exception as e:
|
993
|
+
logger.error(f"Error in _get_prj_entries for {entry_type}: {e}")
|
994
|
+
raise
|
995
|
+
|
996
|
+
def _create_entry(self, entry_type, file_name, full_path):
|
997
|
+
"""Helper method to create entry dictionary."""
|
998
|
+
entry_number = file_name[1:]
|
999
|
+
entry = {
|
1000
|
+
f'{entry_type.lower()}_number': entry_number,
|
1001
|
+
'full_path': full_path,
|
1002
|
+
'unsteady_number': None,
|
1003
|
+
'geometry_number': None
|
1004
|
+
}
|
1005
|
+
|
1006
|
+
if entry_type == 'Unsteady':
|
1007
|
+
entry['unsteady_number'] = entry_number
|
1008
|
+
entry.update(self._parse_unsteady_file(Path(full_path)))
|
1009
|
+
elif entry_type == 'Plan':
|
1010
|
+
self._update_plan_entry(entry, entry_number, full_path)
|
917
1011
|
|
918
|
-
return
|
1012
|
+
return entry
|
1013
|
+
|
1014
|
+
def _update_plan_entry(self, entry, entry_number, full_path):
|
1015
|
+
"""Helper method to update plan entry with additional information."""
|
1016
|
+
plan_info = self._parse_plan_file(Path(full_path))
|
1017
|
+
if plan_info:
|
1018
|
+
# Handle Flow File
|
1019
|
+
flow_file = plan_info.get('Flow File')
|
1020
|
+
if flow_file:
|
1021
|
+
if flow_file.startswith('u'):
|
1022
|
+
entry.update({'unsteady_number': flow_file[1:], 'Flow File': flow_file[1:]})
|
1023
|
+
else:
|
1024
|
+
entry['Flow File'] = flow_file[1:] if flow_file.startswith('f') else None
|
1025
|
+
|
1026
|
+
# Handle Geom File
|
1027
|
+
geom_file = plan_info.get('Geom File')
|
1028
|
+
if geom_file and geom_file.startswith('g'):
|
1029
|
+
entry.update({'geometry_number': geom_file[1:], 'Geom File': geom_file[1:]})
|
1030
|
+
|
1031
|
+
# Add remaining plan info
|
1032
|
+
entry.update({k: v for k, v in plan_info.items() if k not in ['Flow File', 'Geom File']})
|
1033
|
+
|
1034
|
+
# Add HDF results path
|
1035
|
+
hdf_path = self.project_folder / f"{self.project_name}.p{entry_number}.hdf"
|
1036
|
+
entry['HDF_Results_Path'] = str(hdf_path) if hdf_path.exists() else None
|
1037
|
+
|
1038
|
+
def _set_plan_paths(self):
|
1039
|
+
"""Helper method to set paths in plan_df."""
|
1040
|
+
if not self.plan_df['full_path'].any():
|
1041
|
+
self.plan_df['full_path'] = self.plan_df['plan_number'].apply(
|
1042
|
+
lambda x: str(self.project_folder / f"{self.project_name}.p{x}")
|
1043
|
+
)
|
1044
|
+
|
1045
|
+
for idx, row in self.plan_df.iterrows():
|
1046
|
+
if pd.notna(row['Geom File']) and pd.isna(row.get('Geom Path')):
|
1047
|
+
self.plan_df.at[idx, 'Geom Path'] = str(self.project_folder / f"{self.project_name}.g{row['Geom File']}")
|
1048
|
+
|
1049
|
+
if pd.notna(row['Flow File']) and pd.isna(row.get('Flow Path')):
|
1050
|
+
prefix = 'u' if pd.notna(row['unsteady_number']) else 'f'
|
1051
|
+
self.plan_df.at[idx, 'Flow Path'] = str(self.project_folder / f"{self.project_name}.{prefix}{row['Flow File']}")
|
1052
|
+
|
1053
|
+
if not self.suppress_logging:
|
1054
|
+
logger.info(f"Plan {row['plan_number']} paths set up")
|
1055
|
+
|
919
1056
|
|
920
1057
|
# Create a global instance named 'ras'
|
921
1058
|
# Defining the global instance allows the init_ras_project function to initialize the project.
|
@@ -987,7 +1124,7 @@ def get_ras_exe(ras_version=None):
|
|
987
1124
|
Args:
|
988
1125
|
ras_version (str, optional): Either a version number or a full path to the HEC-RAS executable.
|
989
1126
|
If None, the function will first check the global 'ras' object for a path.
|
990
|
-
|
1127
|
+
or a default path.
|
991
1128
|
|
992
1129
|
Returns:
|
993
1130
|
str: The full path to the HEC-RAS executable.
|
ras_commander/RasUtils.py
CHANGED
@@ -216,30 +216,49 @@ class RasUtils:
|
|
216
216
|
Returns:
|
217
217
|
Path: Full path to the plan file
|
218
218
|
|
219
|
+
Raises:
|
220
|
+
ValueError: If plan number is not between 1 and 99
|
221
|
+
TypeError: If input type is invalid
|
222
|
+
FileNotFoundError: If the plan file does not exist
|
223
|
+
|
219
224
|
Example:
|
220
225
|
>>> plan_path = RasUtils.get_plan_path(1)
|
221
226
|
>>> print(f"Plan file path: {plan_path}")
|
222
227
|
>>> plan_path = RasUtils.get_plan_path("path/to/plan.p01")
|
223
228
|
>>> print(f"Plan file path: {plan_path}")
|
224
229
|
"""
|
225
|
-
|
230
|
+
# Validate RAS object
|
226
231
|
ras_obj = ras_object or ras
|
227
232
|
ras_obj.check_initialized()
|
228
233
|
|
234
|
+
# Handle direct file path input
|
229
235
|
plan_path = Path(current_plan_number_or_path)
|
230
236
|
if plan_path.is_file():
|
231
237
|
logger.info(f"Using provided plan file path: {plan_path}")
|
232
238
|
return plan_path
|
233
239
|
|
240
|
+
# Handle plan number input
|
234
241
|
try:
|
235
|
-
|
242
|
+
plan_num = int(current_plan_number_or_path)
|
243
|
+
if not 1 <= plan_num <= 99:
|
244
|
+
raise ValueError(f"Plan number must be between 1 and 99, got: {plan_num}")
|
245
|
+
current_plan_number = f"{plan_num:02d}" # Ensure two-digit format
|
236
246
|
logger.debug(f"Converted plan number to two-digit format: {current_plan_number}")
|
237
|
-
except ValueError:
|
247
|
+
except (ValueError, TypeError) as e:
|
248
|
+
if isinstance(e, TypeError):
|
249
|
+
logger.error(f"Invalid input type: {type(current_plan_number_or_path)}. Expected string, number, or Path.")
|
250
|
+
raise TypeError(f"Invalid input type: {type(current_plan_number_or_path)}. Expected string, number, or Path.")
|
238
251
|
logger.error(f"Invalid plan number: {current_plan_number_or_path}. Expected a number from 1 to 99.")
|
239
252
|
raise ValueError(f"Invalid plan number: {current_plan_number_or_path}. Expected a number from 1 to 99.")
|
240
253
|
|
254
|
+
# Construct and validate plan path
|
241
255
|
plan_name = f"{ras_obj.project_name}.p{current_plan_number}"
|
242
256
|
full_plan_path = ras_obj.project_folder / plan_name
|
257
|
+
|
258
|
+
if not full_plan_path.exists():
|
259
|
+
logger.error(f"Plan file does not exist: {full_plan_path}")
|
260
|
+
raise FileNotFoundError(f"Plan file does not exist: {full_plan_path}")
|
261
|
+
|
243
262
|
logger.info(f"Constructed plan file path: {full_plan_path}")
|
244
263
|
return full_plan_path
|
245
264
|
|
ras_commander/__init__.py
CHANGED
@@ -21,14 +21,14 @@ ras_commander/RasExamples.py,sha256=6IZ96LcAsk5LYFehdD0zDW5wyZWxQa6OQu2N9upxWXA,
|
|
21
21
|
ras_commander/RasGeo.py,sha256=M0sVNKlWmmbve8iMXLWq25WgbxqLWBo7_1oDg_rALzU,5607
|
22
22
|
ras_commander/RasGpt.py,sha256=N_7p2nucWrBBXdB2k2ZKvOeOdXNmFD9dIY3W7_5i5nw,1206
|
23
23
|
ras_commander/RasMapper.py,sha256=LO_blvQnd4pwkEU8A30-RoE-CYIoU3s_fNLHBoM8ljw,613
|
24
|
-
ras_commander/RasPlan.py,sha256=
|
25
|
-
ras_commander/RasPrj.py,sha256=
|
24
|
+
ras_commander/RasPlan.py,sha256=0THxeB9ldeDuS4of2ruYG7Abbc5jz2729y5qOHntMuI,61664
|
25
|
+
ras_commander/RasPrj.py,sha256=gQoGG1Mqsoj5W1oVlulqhA0kQ5eD69vI96uihnY-kLE,47744
|
26
26
|
ras_commander/RasToGo.py,sha256=TKujfaV1xQhFaOddF4g2ogGy6ky-CLlfelSMPD2J3Nk,1223
|
27
27
|
ras_commander/RasUnsteady.py,sha256=KfCXAag-_bPwwS3JbPZH-s4hbaoHACO0mlRnGrzbFgA,32092
|
28
|
-
ras_commander/RasUtils.py,sha256=
|
29
|
-
ras_commander/__init__.py,sha256=
|
30
|
-
ras_commander-0.
|
31
|
-
ras_commander-0.
|
32
|
-
ras_commander-0.
|
33
|
-
ras_commander-0.
|
34
|
-
ras_commander-0.
|
28
|
+
ras_commander/RasUtils.py,sha256=0fm4IIs0LH1dgDj3pGd66mR82DhWLEkRKUvIo2M_5X0,35886
|
29
|
+
ras_commander/__init__.py,sha256=KICL5peRDDjE2BXEFVDMmtDZ4TKHtNhHh5eQgTSdqqs,2001
|
30
|
+
ras_commander-0.66.0.dist-info/LICENSE,sha256=_pbd6qHnlsz1iQ-ozDW_49r86BZT6CRwO2iBtw0iN6M,457
|
31
|
+
ras_commander-0.66.0.dist-info/METADATA,sha256=-jPNaFlPs0iCcscfGjO31DwF3-LT632rbiunJQmYzoM,26233
|
32
|
+
ras_commander-0.66.0.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
33
|
+
ras_commander-0.66.0.dist-info/top_level.txt,sha256=i76S7eKLFC8doKcXDl3aiOr9RwT06G8adI6YuKbQDaA,14
|
34
|
+
ras_commander-0.66.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|