ras-commander 0.34.0__py3-none-any.whl → 0.36.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/RasCmdr.py +362 -333
- ras_commander/RasExamples.py +329 -132
- ras_commander/RasGeo.py +38 -28
- ras_commander/RasGpt.py +142 -0
- ras_commander/RasHdf.py +1480 -109
- ras_commander/RasPlan.py +123 -167
- ras_commander/RasPrj.py +213 -136
- ras_commander/RasUnsteady.py +37 -22
- ras_commander/RasUtils.py +98 -82
- ras_commander/__init__.py +11 -13
- ras_commander/logging_config.py +80 -0
- {ras_commander-0.34.0.dist-info → ras_commander-0.36.0.dist-info}/METADATA +73 -13
- ras_commander-0.36.0.dist-info/RECORD +17 -0
- ras_commander-0.34.0.dist-info/RECORD +0 -15
- {ras_commander-0.34.0.dist-info → ras_commander-0.36.0.dist-info}/LICENSE +0 -0
- {ras_commander-0.34.0.dist-info → ras_commander-0.36.0.dist-info}/WHEEL +0 -0
- {ras_commander-0.34.0.dist-info → ras_commander-0.36.0.dist-info}/top_level.txt +0 -0
ras_commander/RasGeo.py
CHANGED
@@ -1,21 +1,37 @@
|
|
1
1
|
"""
|
2
|
-
Operations for handling geometry files in HEC-RAS projects
|
2
|
+
RasGeo - Operations for handling geometry files in HEC-RAS projects
|
3
|
+
|
4
|
+
This module is part of the ras-commander library and uses a centralized logging configuration.
|
5
|
+
|
6
|
+
Logging Configuration:
|
7
|
+
- The logging is set up in the logging_config.py file.
|
8
|
+
- A @log_call decorator is available to automatically log function calls.
|
9
|
+
- Log levels: DEBUG, INFO, WARNING, ERROR, CRITICAL
|
10
|
+
- Logs are written to both console and a rotating file handler.
|
11
|
+
- The default log file is 'ras_commander.log' in the 'logs' directory.
|
12
|
+
- The default log level is INFO.
|
13
|
+
|
14
|
+
To use logging in this module:
|
15
|
+
1. Use the @log_call decorator for automatic function call logging.
|
16
|
+
2. For additional logging, use logger.[level]() calls (e.g., logger.info(), logger.debug()).
|
17
|
+
3. Obtain the logger using: logger = logging.getLogger(__name__)
|
18
|
+
|
19
|
+
Example:
|
20
|
+
@log_call
|
21
|
+
def my_function():
|
22
|
+
logger = logging.getLogger(__name__)
|
23
|
+
logger.debug("Additional debug information")
|
24
|
+
# Function logic here
|
3
25
|
"""
|
26
|
+
import os
|
4
27
|
from pathlib import Path
|
5
28
|
from typing import List, Union
|
6
29
|
from .RasPlan import RasPlan
|
7
30
|
from .RasPrj import ras
|
8
|
-
import
|
9
|
-
import
|
31
|
+
from ras_commander import get_logger
|
32
|
+
from ras_commander.logging_config import log_call
|
10
33
|
|
11
|
-
|
12
|
-
logging.basicConfig(
|
13
|
-
level=logging.INFO,
|
14
|
-
format='%(asctime)s - %(levelname)s - %(message)s',
|
15
|
-
# You can add a filename parameter here to log to a file
|
16
|
-
# filename='rasgeo.log',
|
17
|
-
# Uncomment the above line to enable file logging
|
18
|
-
)
|
34
|
+
logger = get_logger(__name__)
|
19
35
|
|
20
36
|
class RasGeo:
|
21
37
|
"""
|
@@ -23,6 +39,7 @@ class RasGeo:
|
|
23
39
|
"""
|
24
40
|
|
25
41
|
@staticmethod
|
42
|
+
@log_call
|
26
43
|
def clear_geompre_files(
|
27
44
|
plan_files: Union[str, Path, List[Union[str, Path]]] = None,
|
28
45
|
ras_object = None
|
@@ -58,11 +75,6 @@ class RasGeo:
|
|
58
75
|
Note:
|
59
76
|
This function updates the ras object's geometry dataframe after clearing the preprocessor files.
|
60
77
|
"""
|
61
|
-
## Explicit Function Steps
|
62
|
-
# 1. Initialize the ras_object, defaulting to the global ras if not provided.
|
63
|
-
# 2. Define a helper function to clear a single geometry preprocessor file.
|
64
|
-
# 3. Determine the list of plan files to process based on the input.
|
65
|
-
# 4. Iterate over each plan file and clear its geometry preprocessor file.
|
66
78
|
ras_obj = ras_object or ras
|
67
79
|
ras_obj.check_initialized()
|
68
80
|
|
@@ -72,38 +84,36 @@ class RasGeo:
|
|
72
84
|
geom_preprocessor_file = plan_path.with_suffix(geom_preprocessor_suffix)
|
73
85
|
if geom_preprocessor_file.exists():
|
74
86
|
try:
|
75
|
-
logging.info(f"Deleting geometry preprocessor file: {geom_preprocessor_file}")
|
76
87
|
geom_preprocessor_file.unlink()
|
77
|
-
|
88
|
+
logger.info(f"Deleted geometry preprocessor file: {geom_preprocessor_file}")
|
78
89
|
except PermissionError:
|
79
|
-
|
90
|
+
logger.error(f"Permission denied: Unable to delete geometry preprocessor file: {geom_preprocessor_file}")
|
80
91
|
raise PermissionError(f"Unable to delete geometry preprocessor file: {geom_preprocessor_file}. Permission denied.")
|
81
92
|
except OSError as e:
|
82
|
-
|
93
|
+
logger.error(f"Error deleting geometry preprocessor file: {geom_preprocessor_file}. {str(e)}")
|
83
94
|
raise OSError(f"Error deleting geometry preprocessor file: {geom_preprocessor_file}. {str(e)}")
|
84
95
|
else:
|
85
|
-
|
96
|
+
logger.warning(f"No geometry preprocessor file found for: {plan_file}")
|
86
97
|
|
87
98
|
if plan_files is None:
|
88
|
-
|
99
|
+
logger.info("Clearing all geometry preprocessor files in the project directory.")
|
89
100
|
plan_files_to_clear = list(ras_obj.project_folder.glob(r'*.p*'))
|
90
101
|
elif isinstance(plan_files, (str, Path)):
|
91
102
|
plan_files_to_clear = [plan_files]
|
92
|
-
|
103
|
+
logger.info(f"Clearing geometry preprocessor file for single plan: {plan_files}")
|
93
104
|
elif isinstance(plan_files, list):
|
94
105
|
plan_files_to_clear = plan_files
|
95
|
-
|
106
|
+
logger.info(f"Clearing geometry preprocessor files for multiple plans: {plan_files}")
|
96
107
|
else:
|
97
|
-
|
108
|
+
logger.error("Invalid input type for plan_files.")
|
98
109
|
raise ValueError("Invalid input. Please provide a string, Path, list of paths, or None.")
|
99
110
|
|
100
111
|
for plan_file in plan_files_to_clear:
|
101
112
|
clear_single_file(plan_file, ras_obj)
|
102
113
|
|
103
|
-
# Update the geometry dataframe
|
104
114
|
try:
|
105
115
|
ras_obj.geom_df = ras_obj.get_geom_entries()
|
106
|
-
|
116
|
+
logger.info("Geometry dataframe updated successfully.")
|
107
117
|
except Exception as e:
|
108
|
-
|
118
|
+
logger.error(f"Failed to update geometry dataframe: {str(e)}")
|
109
119
|
raise
|
ras_commander/RasGpt.py
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
import os
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import Optional
|
4
|
+
from ras_commander import get_logger, log_call
|
5
|
+
|
6
|
+
logger = get_logger(__name__)
|
7
|
+
|
8
|
+
class RasGpt:
|
9
|
+
"""
|
10
|
+
A class containing helper functions for the RAS Commander GPT.
|
11
|
+
"""
|
12
|
+
|
13
|
+
# READ Functions to allow GPT to read library files quickly
|
14
|
+
|
15
|
+
@classmethod
|
16
|
+
@log_call
|
17
|
+
def read_library_guide(cls) -> Optional[str]:
|
18
|
+
"""
|
19
|
+
Reads and returns the contents of the Comprehensive_Library_Guide.md file.
|
20
|
+
|
21
|
+
Returns:
|
22
|
+
Optional[str]: The contents of the file, or None if the file is not found.
|
23
|
+
"""
|
24
|
+
file_path = Path(__file__).parent.parent / "docs" / "Comprehensive_Library_Guide.md"
|
25
|
+
return cls._read_file(file_path)
|
26
|
+
|
27
|
+
|
28
|
+
# ADD FOR read_reaadme and read_function_list
|
29
|
+
# Need to add a function list separate from the Library Guide
|
30
|
+
|
31
|
+
# ADD for read_example_list which will read the example folder README.ModuleNotFoundError
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
@classmethod
|
38
|
+
@log_call
|
39
|
+
def read_style_guide(cls) -> Optional[str]:
|
40
|
+
"""
|
41
|
+
Reads and returns the contents of the STYLE_GUIDE.md file.
|
42
|
+
|
43
|
+
Returns:
|
44
|
+
Optional[str]: The contents of the file, or None if the file is not found.
|
45
|
+
"""
|
46
|
+
file_path = Path(__file__).parent.parent / "docs" / "STYLE_GUIDE.md"
|
47
|
+
return cls._read_file(file_path)
|
48
|
+
|
49
|
+
|
50
|
+
# READ CLASS FILE FUNCTIONS:
|
51
|
+
|
52
|
+
@classmethod
|
53
|
+
@log_call
|
54
|
+
def read_class_rascmdr(cls) -> Optional[str]:
|
55
|
+
"""
|
56
|
+
Reads and returns the contents of the RasCmdr.py file.
|
57
|
+
|
58
|
+
Returns:
|
59
|
+
Optional[str]: The contents of the file, or None if the file is not found.
|
60
|
+
"""
|
61
|
+
file_path = Path(__file__).parent / "RasCmdr.py"
|
62
|
+
return cls._read_file(file_path)
|
63
|
+
|
64
|
+
# add one for each class file
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
# Public Helper Functions:
|
71
|
+
|
72
|
+
|
73
|
+
@classmethod
|
74
|
+
@log_call
|
75
|
+
def get_file_structure(cls, directory: Optional[str] = None) -> str:
|
76
|
+
"""
|
77
|
+
Returns a string representation of the file structure of the ras_commander package.
|
78
|
+
|
79
|
+
Args:
|
80
|
+
directory (Optional[str]): The directory to start from. If None, uses the package root.
|
81
|
+
|
82
|
+
Returns:
|
83
|
+
str: A string representation of the file structure.
|
84
|
+
"""
|
85
|
+
if directory is None:
|
86
|
+
directory = Path(__file__).parent
|
87
|
+
|
88
|
+
return cls._get_directory_structure(directory)
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
# Private Helper Functions:
|
94
|
+
|
95
|
+
@staticmethod
|
96
|
+
def _read_file(file_path: Path) -> Optional[str]:
|
97
|
+
"""
|
98
|
+
Helper method to read the contents of a file.
|
99
|
+
|
100
|
+
Args:
|
101
|
+
file_path (Path): The path to the file to be read.
|
102
|
+
|
103
|
+
Returns:
|
104
|
+
Optional[str]: The contents of the file, or None if the file is not found.
|
105
|
+
"""
|
106
|
+
try:
|
107
|
+
with open(file_path, 'r', encoding='utf-8') as file:
|
108
|
+
return file.read()
|
109
|
+
except FileNotFoundError:
|
110
|
+
logger.error(f"File not found: {file_path}")
|
111
|
+
return None
|
112
|
+
except Exception as e:
|
113
|
+
logger.error(f"Error reading file {file_path}: {str(e)}")
|
114
|
+
return None
|
115
|
+
|
116
|
+
|
117
|
+
@staticmethod
|
118
|
+
def _get_directory_structure(directory: Path, prefix: str = "") -> str:
|
119
|
+
"""
|
120
|
+
Helper method to recursively build the directory structure string.
|
121
|
+
|
122
|
+
Args:
|
123
|
+
directory (Path): The directory to process.
|
124
|
+
prefix (str): The prefix to use for the current level.
|
125
|
+
|
126
|
+
Returns:
|
127
|
+
str: A string representation of the directory structure.
|
128
|
+
"""
|
129
|
+
if not directory.is_dir():
|
130
|
+
return ""
|
131
|
+
|
132
|
+
output = []
|
133
|
+
for item in sorted(directory.iterdir()):
|
134
|
+
if item.name.startswith('.'):
|
135
|
+
continue
|
136
|
+
if item.is_dir():
|
137
|
+
output.append(f"{prefix}{item.name}/")
|
138
|
+
output.append(RasGpt._get_directory_structure(item, prefix + " "))
|
139
|
+
else:
|
140
|
+
output.append(f"{prefix}{item.name}")
|
141
|
+
|
142
|
+
return "\n".join(output)
|