初始提交,未完全测试
This commit is contained in:
166
kit/Prop.py
Normal file
166
kit/Prop.py
Normal file
@@ -0,0 +1,166 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user