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/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 logging
9
- import re
31
+ from ras_commander import get_logger
32
+ from ras_commander.logging_config import log_call
10
33
 
11
- # Configure logging at the module level
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
- logging.info("File deletion completed successfully.")
88
+ logger.info(f"Deleted geometry preprocessor file: {geom_preprocessor_file}")
78
89
  except PermissionError:
79
- logging.error(f"Permission denied: Unable to delete geometry preprocessor file: {geom_preprocessor_file}.")
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
- logging.error(f"Error deleting geometry preprocessor file: {geom_preprocessor_file}. {str(e)}")
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
- logging.warning(f"No geometry preprocessor file found for: {plan_file}")
96
+ logger.warning(f"No geometry preprocessor file found for: {plan_file}")
86
97
 
87
98
  if plan_files is None:
88
- logging.info("Clearing all geometry preprocessor files in the project directory.")
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
- logging.info(f"Clearing geometry preprocessor file for single plan: {plan_files}")
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
- logging.info(f"Clearing geometry preprocessor files for multiple plans: {plan_files}")
106
+ logger.info(f"Clearing geometry preprocessor files for multiple plans: {plan_files}")
96
107
  else:
97
- logging.error("Invalid input type for plan_files.")
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
- logging.info("Geometry dataframe updated successfully.")
116
+ logger.info("Geometry dataframe updated successfully.")
107
117
  except Exception as e:
108
- logging.error(f"Failed to update geometry dataframe: {str(e)}")
118
+ logger.error(f"Failed to update geometry dataframe: {str(e)}")
109
119
  raise
@@ -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)