#!/usr/bin/env python3.9 # -*- coding: utf-8 -*- """ JFinal Prop - Properties File Handler """ import os from typing import Optional class Prop: """Properties file handler""" DEFAULT_ENCODING = "UTF-8" def __init__(self, file_name_or_content=None, encoding: str = DEFAULT_ENCODING, is_file: bool = True): """ Initialize Prop Args: file_name_or_content: file name (if is_file=True) or content string encoding: encoding for reading properties file is_file: True if first parameter is file name, False if it's content string """ self._properties = {} if file_name_or_content is None: return if is_file: self._load_from_file(file_name_or_content, encoding) else: self._load_from_content(file_name_or_content, encoding) def _load_from_file(self, file_name: str, encoding: str): """Load properties from file""" try: # Try to find file in classpath first import importlib.resources try: with importlib.resources.open_text(file_name, encoding=encoding) as f: self._parse_properties(f.read()) return except (FileNotFoundError, TypeError): pass # Try as absolute file path if os.path.isabs(file_name): file_path = file_name else: file_path = os.path.join(os.getcwd(), file_name) if not os.path.exists(file_path): raise FileNotFoundError(f"Properties file not found: {file_name}") with open(file_path, 'r', encoding=encoding) as f: self._parse_properties(f.read()) except Exception as e: raise RuntimeError(f"Error loading properties file: {e}") def _load_from_content(self, content: str, encoding: str): """Load properties from content string""" try: self._parse_properties(content) except Exception as e: raise RuntimeError(f"Error parsing properties content: {e}") def _parse_properties(self, content: str): """Parse properties content""" for line in content.split('\n'): line = line.strip() # Skip empty lines and comments if not line or line.startswith('#') or line.startswith('!'): continue # Handle line continuation while line.endswith('\\'): line = line[:-1].strip() # This is a simplified implementation # Find the first separator separator_idx = -1 for sep in ['=', ':']: idx = line.find(sep) if idx != -1: if separator_idx == -1 or idx < separator_idx: separator_idx = idx if separator_idx == -1: # No separator, treat as key with empty value key = line.strip() value = "" else: key = line[:separator_idx].strip() value = line[separator_idx + 1:].strip() if key: self._properties[key] = value def get(self, key: str, default_value: str = None) -> Optional[str]: """Get property value""" value = self._properties.get(key) if value is not None and len(value) != 0: return value.strip() return default_value def get_int(self, key: str, default_value: int = None) -> Optional[int]: """Get property as integer""" value = self.get(key) if value is not None: return int(value) return default_value def get_long(self, key: str, default_value: int = None) -> Optional[int]: """Get property as long integer""" value = self.get(key) if value is not None: return int(value) return default_value def get_double(self, key: str, default_value: float = None) -> Optional[float]: """Get property as double""" value = self.get(key) if value is not None: return float(value) return default_value def get_boolean(self, key: str, default_value: bool = None) -> Optional[bool]: """Get property as boolean""" value = self.get(key) if value is not None: value_lower = value.lower().strip() if value_lower == "true": return True elif value_lower == "false": return False else: raise ValueError(f"Cannot parse boolean value: {value}") return default_value def contains_key(self, key: str) -> bool: """Check if key exists""" return key in self._properties def is_empty(self) -> bool: """Check if properties is empty""" return len(self._properties) == 0 def not_empty(self) -> bool: """Check if properties is not empty""" return not self.is_empty() def append(self, prop) -> 'Prop': """Append properties from another Prop""" if prop is None: raise ValueError("prop cannot be None") for key, value in prop.get_properties().items(): self._properties[key] = value return self def get_properties(self) -> dict: """Get all properties""" return self._properties.copy()