mdbq 4.0.22__tar.gz → 4.0.24__tar.gz

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.
Files changed (36) hide show
  1. {mdbq-4.0.22 → mdbq-4.0.24}/PKG-INFO +1 -1
  2. mdbq-4.0.24/mdbq/__version__.py +1 -0
  3. mdbq-4.0.22/mdbq/myconf/myconf2.py → mdbq-4.0.24/mdbq/myconf/myconf.py +259 -159
  4. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq.egg-info/PKG-INFO +1 -1
  5. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq.egg-info/SOURCES.txt +1 -1
  6. mdbq-4.0.22/mdbq/__version__.py +0 -1
  7. {mdbq-4.0.22 → mdbq-4.0.24}/README.txt +0 -0
  8. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/__init__.py +0 -0
  9. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/aggregation/__init__.py +0 -0
  10. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/aggregation/query_data.py +0 -0
  11. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/log/__init__.py +0 -0
  12. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/log/mylogger.py +0 -0
  13. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/myconf/__init__.py +0 -0
  14. /mdbq-4.0.22/mdbq/myconf/myconf.py → /mdbq-4.0.24/mdbq/myconf/myconf_bak.py +0 -0
  15. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/mysql/__init__.py +0 -0
  16. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/mysql/deduplicator.py +0 -0
  17. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/mysql/mysql.py +0 -0
  18. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/mysql/s_query.py +0 -0
  19. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/mysql/unique_.py +0 -0
  20. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/mysql/uploader.py +0 -0
  21. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/other/__init__.py +0 -0
  22. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/other/download_sku_picture.py +0 -0
  23. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/other/otk.py +0 -0
  24. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/other/pov_city.py +0 -0
  25. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/other/ua_sj.py +0 -0
  26. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/pbix/__init__.py +0 -0
  27. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/pbix/pbix_refresh.py +0 -0
  28. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/pbix/refresh_all.py +0 -0
  29. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/redis/__init__.py +0 -0
  30. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/redis/getredis.py +0 -0
  31. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/spider/__init__.py +0 -0
  32. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq/spider/aikucun.py +0 -0
  33. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq.egg-info/dependency_links.txt +0 -0
  34. {mdbq-4.0.22 → mdbq-4.0.24}/mdbq.egg-info/top_level.txt +0 -0
  35. {mdbq-4.0.22 → mdbq-4.0.24}/setup.cfg +0 -0
  36. {mdbq-4.0.22 → mdbq-4.0.24}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: mdbq
3
- Version: 4.0.22
3
+ Version: 4.0.24
4
4
  Home-page: https://pypi.org/project/mdbq
5
5
  Author: xigua,
6
6
  Author-email: 2587125111@qq.com
@@ -0,0 +1 @@
1
+ VERSION = '4.0.24'
@@ -21,14 +21,16 @@ logger = mylogger.MyLogger(
21
21
  T = TypeVar('T') # 类型变量
22
22
 
23
23
 
24
- class ConfigError(Exception):
25
- """配置相关的基础异常类"""
24
+ class ConfigException(Exception):
25
+ """配置异常基类"""
26
26
  def __init__(self, message: str, file_path: Optional[Union[str, Path]] = None,
27
- section: Optional[str] = None, key: Optional[str] = None):
27
+ section: Optional[str] = None, key: Optional[str] = None,
28
+ original_error: Optional[Exception] = None):
28
29
  self.message = message
29
30
  self.file_path = str(file_path) if file_path else None
30
31
  self.section = section
31
32
  self.key = key
33
+ self.original_error = original_error
32
34
  super().__init__(self._format_message())
33
35
 
34
36
  def _format_message(self) -> str:
@@ -40,62 +42,69 @@ class ConfigError(Exception):
40
42
  parts.append(f"节: [{self.section}]")
41
43
  if self.key:
42
44
  parts.append(f"键: {self.key}")
45
+ if self.original_error:
46
+ parts.append(f"原始错误: {str(self.original_error)}")
43
47
  return " | ".join(parts)
44
48
 
45
-
46
- class ConfigFileNotFoundError(ConfigError):
47
- """配置文件不存在异常"""
48
- def __init__(self, file_path: Union[str, Path]):
49
- super().__init__("配置文件不存在", file_path=file_path)
50
-
51
-
52
- class ConfigReadError(ConfigError):
53
- """读取配置文件失败异常"""
54
- def __init__(self, file_path: Union[str, Path], original_error: Exception):
55
- super().__init__(
56
- f"读取配置文件失败: {str(original_error)}",
57
- file_path=file_path
58
- )
59
- self.original_error = original_error
60
-
61
-
62
- class ConfigWriteError(ConfigError):
63
- """写入配置文件失败异常"""
64
- def __init__(self, file_path: Union[str, Path], original_error: Exception):
65
- super().__init__(
66
- f"写入配置文件失败: {str(original_error)}",
67
- file_path=file_path
68
- )
69
- self.original_error = original_error
70
-
71
-
72
- class ConfigValueError(ConfigError):
73
- """配置值无效异常"""
74
- def __init__(self, message: str, file_path: Union[str, Path],
75
- section: Optional[str] = None, key: Optional[str] = None):
76
- super().__init__(message, file_path=file_path, section=section, key=key)
77
-
78
-
79
- class ConfigSectionNotFoundError(ConfigError):
80
- """配置节不存在异常"""
81
- def __init__(self, file_path: Union[str, Path], section: str):
82
- super().__init__(
83
- f"配置节不存在",
84
- file_path=file_path,
85
- section=section
86
- )
87
-
88
-
89
- class ConfigKeyNotFoundError(ConfigError):
90
- """配置键不存在异常"""
91
- def __init__(self, file_path: Union[str, Path], section: str, key: str):
92
- super().__init__(
93
- f"配置键不存在",
49
+ @classmethod
50
+ def file_not_found(cls, file_path: Union[str, Path]) -> 'ConfigException':
51
+ """配置文件不存在异常"""
52
+ return cls("配置文件不存在", file_path=file_path)
53
+
54
+ @classmethod
55
+ def read_error(cls, file_path: Union[str, Path], error: Exception) -> 'ConfigException':
56
+ """读取配置文件失败异常"""
57
+ return cls("读取配置文件失败", file_path=file_path, original_error=error)
58
+
59
+ @classmethod
60
+ def write_error(cls, file_path: Union[str, Path], error: Exception) -> 'ConfigException':
61
+ """写入配置文件失败异常"""
62
+ return cls("写入配置文件失败", file_path=file_path, original_error=error)
63
+
64
+ @classmethod
65
+ def value_error(cls, message: str, file_path: Union[str, Path],
66
+ section: Optional[str] = None, key: Optional[str] = None) -> 'ConfigException':
67
+ """配置值无效异常"""
68
+ return cls(message, file_path=file_path, section=section, key=key)
69
+
70
+ @classmethod
71
+ def section_not_found(cls, file_path: Union[str, Path], section: str) -> 'ConfigException':
72
+ """配置节不存在异常"""
73
+ return cls("配置节不存在", file_path=file_path, section=section)
74
+
75
+ @classmethod
76
+ def key_not_found(cls, file_path: Union[str, Path], section: str, key: str) -> 'ConfigException':
77
+ """配置键不存在异常"""
78
+ return cls("配置键不存在", file_path=file_path, section=section, key=key)
79
+
80
+ @classmethod
81
+ def validation_error(cls, message: str, file_path: Union[str, Path],
82
+ section: Optional[str] = None, key: Optional[str] = None) -> 'ConfigException':
83
+ """配置验证失败异常"""
84
+ return cls(f"配置验证失败: {message}", file_path=file_path, section=section, key=key)
85
+
86
+ @classmethod
87
+ def conversion_error(cls, value: Any, target_type: Type, file_path: Union[str, Path],
88
+ section: Optional[str] = None, key: Optional[str] = None) -> 'ConfigException':
89
+ """类型转换失败异常"""
90
+ return cls(
91
+ f"无法将值 '{value}' 转换为类型 {target_type.__name__}",
94
92
  file_path=file_path,
95
93
  section=section,
96
94
  key=key
97
95
  )
98
96
 
97
+ @classmethod
98
+ def invalid_key_error(cls, key: str, file_path: Union[str, Path],
99
+ section: Optional[str] = None) -> 'ConfigException':
100
+ """无效的键名异常"""
101
+ return cls(f"无效的键名: {key}", file_path=file_path, section=section, key=key)
102
+
103
+ @classmethod
104
+ def invalid_section_error(cls, section: str, file_path: Union[str, Path]) -> 'ConfigException':
105
+ """无效的节名异常"""
106
+ return cls(f"无效的节名: {section}", file_path=file_path, section=section)
107
+
99
108
 
100
109
  class CommentStyle(Enum):
101
110
  """配置文件支持的注释风格"""
@@ -143,14 +152,14 @@ class ConfigParser:
143
152
  """打开配置文件"""
144
153
  file_path = Path(file_path)
145
154
  if not file_path.exists() and not self.options.auto_create:
146
- raise ConfigFileNotFoundError(file_path)
155
+ raise ConfigException.file_not_found(file_path)
147
156
  self._current_file = file_path
148
157
  return self
149
158
 
150
159
  def _ensure_file_open(self) -> None:
151
160
  """确保文件已打开"""
152
161
  if self._current_file is None:
153
- raise ConfigError("未打开任何配置文件,请先调用 open() 方法")
162
+ raise ConfigException("未打开任何配置文件,请先调用 open() 方法")
154
163
 
155
164
  def _is_comment_line(self, line: str) -> bool:
156
165
  """判断是否为注释行"""
@@ -204,7 +213,7 @@ class ConfigParser:
204
213
 
205
214
  def _normalize_section(self, section: str) -> str:
206
215
  """标准化节名称"""
207
- return section if self.options.case_sensitive else section.lower()
216
+ return section.replace(' ', '').lower()
208
217
 
209
218
  def _get_original_section(self, file_path: str, normalized_section: str) -> Optional[str]:
210
219
  """获取原始节名称"""
@@ -233,7 +242,7 @@ class ConfigParser:
233
242
  self._comments_cache.clear()
234
243
  self._section_map.clear()
235
244
 
236
- def _convert_value(self, value: str, target_type: Type[T]) -> T:
245
+ def _convert_value(self, value: str, target_type: Type[T], file_path: Optional[Union[str, Path]] = None, key: Optional[str] = None) -> T:
237
246
  """转换配置值到指定类型"""
238
247
  try:
239
248
  if target_type == bool:
@@ -252,13 +261,14 @@ class ConfigParser:
252
261
  if sep in value:
253
262
  return tuple(item.strip() for item in value.split(sep) if item.strip())
254
263
  return (value.strip(),)
255
- elif target_type == set:
264
+ elif target_type == set or target_type == frozenset:
256
265
  if not value.strip():
257
- return set()
266
+ return set() if target_type == set else frozenset()
258
267
  for sep in [',', ';', '|', ' ']:
259
268
  if sep in value:
260
- return {item.strip() for item in value.split(sep) if item.strip()}
261
- return {value.strip()}
269
+ items = [item.strip() for item in value.split(sep) if item.strip()]
270
+ return set(items) if target_type == set else frozenset(items)
271
+ return set([value.strip()]) if target_type == set else frozenset([value.strip()])
262
272
  elif target_type == dict:
263
273
  if not value.strip():
264
274
  return {}
@@ -268,12 +278,12 @@ class ConfigParser:
268
278
  pairs = [pair.strip() for pair in value.split(sep) if pair.strip()]
269
279
  for pair in pairs:
270
280
  if '=' in pair:
271
- key, val = pair.split('=', 1)
272
- result[key.strip()] = val.strip()
281
+ key_, val = pair.split('=', 1)
282
+ result[key_.strip()] = val.strip()
273
283
  return result
274
284
  if '=' in value:
275
- key, val = value.split('=', 1)
276
- return {key.strip(): val.strip()}
285
+ key_, val = value.split('=', 1)
286
+ return {key_.strip(): val.strip()}
277
287
  return {}
278
288
  elif target_type == int:
279
289
  value = value.strip().lower()
@@ -292,10 +302,6 @@ class ConfigParser:
292
302
  return value.encode('utf-8')
293
303
  elif target_type == bytearray:
294
304
  return bytearray(value.encode('utf-8'))
295
- elif target_type == set:
296
- return set(value.split(','))
297
- elif target_type == frozenset:
298
- return frozenset(value.split(','))
299
305
  elif target_type == range:
300
306
  parts = value.split(':')
301
307
  if len(parts) == 2:
@@ -305,48 +311,38 @@ class ConfigParser:
305
311
  raise ValueError("Invalid range format")
306
312
  return target_type(value)
307
313
  except (ValueError, TypeError) as e:
308
- raise ConfigValueError(
309
- f"无法将值 '{value}' 转换为类型 {target_type.__name__}",
310
- file_path=None,
311
- key=None
312
- )
314
+ raise ConfigException.conversion_error(value, target_type, file_path, key=key)
313
315
 
314
- def get_value(self, file_path: Optional[Union[str, Path]] = None, key: str = None,
315
- section: Optional[str] = None, default: Any = None,
316
- value_type: Optional[Type[T]] = None) -> T:
316
+ def get_value(self, section: Optional[str] = None, key: str = None,
317
+ default: Any = None, value_type: Optional[Type[T]] = None,
318
+ file_path: Optional[Union[str, Path]] = None) -> T:
317
319
  """获取指定配置项的值"""
318
320
  if file_path is None:
319
321
  self._ensure_file_open()
320
322
  file_path = self._current_file
321
323
  if not self._validate_key(key):
322
- raise ConfigValueError(f"无效的键名: {key}", file_path=file_path, key=key)
323
-
324
+ raise ConfigException.invalid_key_error(key, file_path, section)
324
325
  config = self.read(file_path)
325
326
  section = section or self.options.default_section
326
327
  normalized_section = self._normalize_section(section)
327
-
328
328
  original_section = self._get_original_section(str(file_path), normalized_section)
329
329
  if original_section is None:
330
330
  if default is not None:
331
331
  return default
332
- raise ConfigSectionNotFoundError(file_path, section)
333
-
332
+ raise ConfigException.section_not_found(file_path, section)
334
333
  if key not in config[original_section]:
335
334
  if default is not None:
336
335
  return default
337
- raise ConfigKeyNotFoundError(file_path, original_section, key)
338
-
336
+ raise ConfigException.key_not_found(file_path, original_section, key)
339
337
  value = config[original_section][key]
340
-
341
338
  if value_type is not None:
342
- return self._convert_value(value, value_type)
343
-
339
+ return self._convert_value(value, value_type, file_path=file_path, key=key)
344
340
  return value
345
341
 
346
- def get_values(self, keys: List[Tuple[str, str]],
347
- file_path: Optional[Union[str, Path]] = None,
342
+ def get_values(self, section: Optional[str] = None, keys: List[Tuple[str, str]] = None,
348
343
  defaults: Optional[Dict[str, Any]] = None,
349
- value_types: Optional[Dict[str, Type]] = None) -> Dict[str, Any]:
344
+ value_types: Optional[Dict[str, Type]] = None,
345
+ file_path: Optional[Union[str, Path]] = None) -> Dict[str, Any]:
350
346
  """批量获取多个配置项的值"""
351
347
  if file_path is None:
352
348
  self._ensure_file_open()
@@ -358,14 +354,15 @@ class ConfigParser:
358
354
  for section, key in keys:
359
355
  try:
360
356
  value = self.get_value(
361
- file_path=file_path,
362
- key=key,
363
357
  section=section,
358
+ key=key,
364
359
  default=defaults.get(key),
365
- value_type=value_types.get(key)
360
+ value_type=value_types.get(key),
361
+ file_path=file_path
366
362
  )
367
363
  result[key] = value
368
- except (ConfigSectionNotFoundError, ConfigKeyNotFoundError) as e:
364
+ except ConfigException as e:
365
+ logger.error(f"读取配置项失败: section={section}, key={key}, error={e}")
369
366
  if key in defaults:
370
367
  result[key] = defaults[key]
371
368
  else:
@@ -373,11 +370,10 @@ class ConfigParser:
373
370
 
374
371
  return result
375
372
 
376
- def get_section_values(self, keys: List[str],
377
- section: Optional[str] = None,
378
- file_path: Optional[Union[str, Path]] = None,
373
+ def get_section_values(self, section: Optional[str] = None, keys: List[str] = None,
379
374
  defaults: Optional[Dict[str, Any]] = None,
380
- value_types: Optional[Dict[str, Type]] = None) -> Tuple[Any, ...]:
375
+ value_types: Optional[Dict[str, Type]] = None,
376
+ file_path: Optional[Union[str, Path]] = None) -> Tuple[Any, ...]:
381
377
  """获取指定节点下多个键的值元组"""
382
378
  if file_path is None:
383
379
  self._ensure_file_open()
@@ -389,14 +385,15 @@ class ConfigParser:
389
385
  for key in keys:
390
386
  try:
391
387
  value = self.get_value(
392
- file_path=file_path,
393
- key=key,
394
388
  section=section,
389
+ key=key,
395
390
  default=defaults.get(key),
396
- value_type=value_types.get(key)
391
+ value_type=value_types.get(key),
392
+ file_path=file_path
397
393
  )
398
394
  result.append(value)
399
- except (ConfigSectionNotFoundError, ConfigKeyNotFoundError) as e:
395
+ except ConfigException as e:
396
+ logger.error(f"读取配置项失败: section={section}, key={key}, error={e}")
400
397
  if key in defaults:
401
398
  result.append(defaults[key])
402
399
  else:
@@ -404,27 +401,23 @@ class ConfigParser:
404
401
 
405
402
  return tuple(result)
406
403
 
407
- def set_value(self, key: str, value: Any,
408
- section: Optional[str] = None,
409
- file_path: Optional[Union[str, Path]] = None,
410
- value_type: Optional[Type] = None) -> None:
404
+ def set_value(self, section: Optional[str] = None, key: str = None, value: Any = None,
405
+ value_type: Optional[Type] = None,
406
+ file_path: Optional[Union[str, Path]] = None) -> None:
411
407
  """设置指定配置项的值"""
412
408
  if file_path is None:
413
409
  self._ensure_file_open()
414
410
  file_path = self._current_file
415
411
  if not self._validate_key(key):
416
- raise ConfigValueError(f"无效的键名: {key}", file_path=file_path, key=key)
417
-
412
+ raise ConfigException.invalid_key_error(key, file_path, section)
413
+ section = section or self.options.default_section
418
414
  original_lines = []
419
415
  if file_path.exists():
420
416
  with open(file_path, 'r', encoding=self.options.encoding) as file:
421
417
  original_lines = file.readlines()
422
-
423
418
  config = self.read(file_path)
424
-
425
419
  if section not in config:
426
420
  config[section] = {}
427
-
428
421
  if value_type is not None:
429
422
  try:
430
423
  if value_type == bool:
@@ -435,43 +428,29 @@ class ConfigParser:
435
428
  else:
436
429
  value = value_type(value)
437
430
  except (ValueError, TypeError) as e:
438
- raise ConfigValueError(
439
- f"无法将值 '{value}' 转换为类型 {value_type.__name__}",
440
- file_path=file_path,
441
- section=section,
442
- key=key
443
- )
444
-
431
+ raise ConfigException.conversion_error(value, value_type, file_path, section=section, key=key)
445
432
  if isinstance(value, bool):
446
433
  value = str(value).lower()
447
434
  else:
448
435
  value = str(value)
449
-
450
436
  config[section][key] = value
451
-
452
437
  try:
453
438
  file_path.parent.mkdir(parents=True, exist_ok=True)
454
-
455
439
  with open(file_path, 'w', encoding=self.options.encoding) as file:
456
440
  current_section = self.options.default_section
457
441
  section_separators = {}
458
-
459
442
  for line in original_lines:
460
443
  stripped_line = line.strip()
461
-
462
444
  if not stripped_line:
463
445
  file.write(line)
464
446
  continue
465
-
466
447
  if stripped_line.startswith('[') and stripped_line.endswith(']'):
467
448
  current_section = stripped_line[1:-1]
468
449
  file.write(line)
469
450
  continue
470
-
471
451
  if self._is_comment_line(stripped_line):
472
452
  file.write(line)
473
453
  continue
474
-
475
454
  key_value = self._split_key_value(stripped_line)
476
455
  if key_value:
477
456
  orig_key, orig_value = key_value
@@ -479,7 +458,6 @@ class ConfigParser:
479
458
  if sep in line:
480
459
  section_separators.setdefault(current_section, {})[orig_key] = sep
481
460
  break
482
-
483
461
  if current_section == section and orig_key == key:
484
462
  separator = section_separators.get(current_section, {}).get(orig_key, self.options.separators[0])
485
463
  comment = ''
@@ -493,15 +471,47 @@ class ConfigParser:
493
471
  file.write(line)
494
472
  else:
495
473
  file.write(line)
496
-
497
474
  if section not in [line.strip()[1:-1] for line in original_lines if line.strip().startswith('[') and line.strip().endswith(']')]:
498
475
  file.write(f'\n[{section}]\n')
499
476
  file.write(f'{key}={value}\n')
500
-
501
477
  self._clear_cache(str(file_path))
502
-
503
478
  except Exception as e:
504
- raise ConfigWriteError(file_path, e)
479
+ raise ConfigException.write_error(file_path, e)
480
+
481
+ def set_values(self, section: Optional[str] = None, values: Dict[str, Any] = None,
482
+ value_types: Optional[Dict[str, Type]] = None,
483
+ file_path: Optional[Union[str, Path]] = None) -> None:
484
+ """批量设置多个配置项的值"""
485
+ for key, value in values.items():
486
+ value_type = value_types.get(key) if value_types else None
487
+ self.set_value(section, key, value, value_type, file_path)
488
+
489
+ def validate_config(self, section: Optional[str] = None, schema: Dict[str, Type] = None,
490
+ file_path: Optional[Union[str, Path]] = None) -> bool:
491
+ """验证配置是否符合指定的模式"""
492
+ config = self.read(file_path)
493
+ if section:
494
+ if section not in config:
495
+ return False
496
+ for key, expected_type in schema.items():
497
+ if key not in config[section]:
498
+ return False
499
+ try:
500
+ self._convert_value(config[section][key], expected_type)
501
+ except ConfigException:
502
+ return False
503
+ else:
504
+ for section, keys in schema.items():
505
+ if section not in config:
506
+ return False
507
+ for key, expected_type in keys.items():
508
+ if key not in config[section]:
509
+ return False
510
+ try:
511
+ self._convert_value(config[section][key], expected_type)
512
+ except ConfigException:
513
+ return False
514
+ return True
505
515
 
506
516
  def read(self, file_path: Optional[Union[str, Path]] = None) -> Dict[str, Any]:
507
517
  """读取配置文件内容"""
@@ -517,7 +527,7 @@ class ConfigParser:
517
527
 
518
528
  if not file_path.exists():
519
529
  if not self.options.auto_create:
520
- raise ConfigFileNotFoundError(file_path)
530
+ raise ConfigException.file_not_found(file_path)
521
531
  logger.info(f'配置文件不存在,将创建: {file_path}')
522
532
  file_path.parent.mkdir(parents=True, exist_ok=True)
523
533
  file_path.touch()
@@ -540,11 +550,7 @@ class ConfigParser:
540
550
  if stripped_line.startswith('[') and stripped_line.endswith(']'):
541
551
  current_section = stripped_line[1:-1]
542
552
  if not self._validate_key(current_section):
543
- raise ConfigValueError(
544
- f"无效的节名: {current_section}",
545
- file_path=file_path,
546
- section=current_section
547
- )
553
+ raise ConfigException.invalid_section_error(current_section, file_path)
548
554
  self._update_section_map(str(file_path), current_section)
549
555
  if current_section not in config:
550
556
  config[current_section] = {}
@@ -557,12 +563,7 @@ class ConfigParser:
557
563
  if key_value:
558
564
  key, value = key_value
559
565
  if not self._validate_key(key):
560
- raise ConfigValueError(
561
- f"无效的键名: {key}",
562
- file_path=file_path,
563
- section=current_section,
564
- key=key
565
- )
566
+ raise ConfigException.invalid_key_error(key, file_path, current_section)
566
567
  value, comment = self._extract_comment(value)
567
568
 
568
569
  if self.options.strip_values:
@@ -579,42 +580,141 @@ class ConfigParser:
579
580
  return config
580
581
 
581
582
  except Exception as e:
582
- raise ConfigReadError(file_path, e)
583
+ raise ConfigException.read_error(file_path, e)
583
584
 
584
585
 
585
586
  def main() -> None:
586
587
  """示例用法"""
587
- config_file = Path('/Users/xigua/spd.txt')
588
-
588
+ config_file = Path('/Users/xigua/spd_副本.txt')
589
+
590
+ # 创建配置解析器实例
591
+ parser = ConfigParser()
592
+ # 设置配置选项
593
+ options = ConfigOptions(
594
+ comment_styles=[CommentStyle.HASH, CommentStyle.DOUBLE_SLASH],
595
+ encoding='utf-8',
596
+ auto_create=True,
597
+ strip_values=True,
598
+ preserve_comments=True,
599
+ default_section='DEFAULT',
600
+ separators=['=', ':', ':'],
601
+ cache_ttl=300,
602
+ validate_keys=True,
603
+ key_pattern=r'^[a-zA-Z0-9_\-\.]+$',
604
+ case_sensitive=False
605
+ )
606
+ parser = ConfigParser(options)
607
+
589
608
  # 方式1:使用上下文管理器
590
609
  with ConfigParser() as parser:
591
610
  parser.open(config_file)
611
+ # 读取配置 - 最常用的参数放在前面
592
612
  host, port, username, password = parser.get_section_values(
593
- keys=['host', 'port', 'username', 'password'],
594
- section='mysql'
613
+ section='mysql', # 最常用的section参数放在前面
614
+ keys=['host', 'port', 'username', 'password']
595
615
  )
596
- print("方式1结果:", host, port, username, password)
597
-
598
- parser.set_value('username', 'root', section='mysql')
599
- parser.set_value('port', 3306, section='mysql')
600
-
616
+ print("2.1 使用上下文管理器 读取结果:", host, port, username, password)
617
+ # 修改配置
618
+ parser.set_value(
619
+ section='mysql',
620
+ key='username',
621
+ value='root'
622
+ )
623
+ parser.set_value(
624
+ section='mysql',
625
+ key='port',
626
+ value=3306,
627
+ value_type=int
628
+ )
629
+
601
630
  # 方式2:链式调用
602
631
  parser = ConfigParser()
603
632
  host, port, username, password = parser.open(config_file).get_section_values(
604
- keys=['host', 'port', 'username', 'password'],
605
- section='mysql'
633
+ section='mysql',
634
+ keys=['host', 'port', 'username', 'password']
606
635
  )
607
- print("\n方式2结果:", host, port, username, password)
608
-
636
+ print("2.2 链式调用 读取结果:", host, port, username, password)
637
+
609
638
  # 方式3:传统方式
610
639
  parser = ConfigParser()
611
640
  host, port, username, password = parser.get_section_values(
612
- file_path=config_file,
613
641
  section='mysql',
614
- keys=['host', 'port', 'username', 'password']
642
+ keys=['host', 'port', 'username', 'password'],
643
+ file_path=config_file # 文件路径参数放在最后
644
+ )
645
+ print("2.3 传统方式 读取结果:", host, port, username, password)
646
+
647
+ # 3.1 读取单个值 - 最常用的参数放在前面
648
+ value = parser.get_value(
649
+ section='mysql',
650
+ key='host',
651
+ default='localhost', # 默认值参数放在中间
652
+ value_type=str,
653
+ file_path=config_file
654
+ )
655
+ print("3.1 单个值读取结果:", value)
656
+
657
+ # 3.2 批量读取多个值 - 最常用的参数放在前面
658
+ values = parser.get_values(
659
+ section='mysql',
660
+ keys=[('host', 'host'), ('host', 'port')],
661
+ defaults={'host': 'localhost', 'port': 3306},
662
+ value_types={'port': int},
663
+ file_path=config_file
664
+ )
665
+ print("3.2 批量读取多个值结果:", values)
666
+
667
+ # 3.3 读取整个配置
668
+ config = parser.read(config_file)
669
+ print("3.3 读取完整配置:", config)
670
+
671
+ # 4.1 写入单个值 - 最常用的参数放在前面
672
+ parser.set_value(
673
+ section='mysql',
674
+ key='host',
675
+ value='127.0.0.1',
676
+ value_type=str,
677
+ file_path=config_file
678
+ )
679
+ print("4.1 写入单个值结果:", config_file)
680
+
681
+ # 4.2 写入不同类型的数据 - 最常用的参数放在前面
682
+ parser.open(config_file)
683
+ parser.set_value(
684
+ section='mysql',
685
+ key='port',
686
+ value=3306,
687
+ value_type=int
688
+ )
689
+ parser.set_value(
690
+ section='mysql',
691
+ key='debug',
692
+ value=True,
693
+ value_type=bool
694
+ )
695
+ parser.set_value(
696
+ section='mysql',
697
+ key='servers',
698
+ value=['server1', 'server2'],
699
+ value_type=list
615
700
  )
616
- print("\n方式3结果:", host, port, username, password)
701
+ print("4.2 写入不同类型的数据")
702
+
703
+ try:
704
+ # 尝试读取不存在的配置项 - 最常用的参数放在前面
705
+ parser.get_value(
706
+ section='mysql',
707
+ key='nonexistent'
708
+ )
709
+ except ConfigException as e:
710
+ if "配置键不存在" in str(e):
711
+ print("5.1 错误处理 配置键不存在错误:", e)
712
+ elif "配置节不存在" in str(e):
713
+ print("5.2 错误处理 配置节不存在错误:", e)
714
+ else:
715
+ print("5.3 错误处理 配置错误:", e)
617
716
 
618
717
 
619
718
  if __name__ == '__main__':
620
719
  main()
720
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: mdbq
3
- Version: 4.0.22
3
+ Version: 4.0.24
4
4
  Home-page: https://pypi.org/project/mdbq
5
5
  Author: xigua,
6
6
  Author-email: 2587125111@qq.com
@@ -12,7 +12,7 @@ mdbq/log/__init__.py
12
12
  mdbq/log/mylogger.py
13
13
  mdbq/myconf/__init__.py
14
14
  mdbq/myconf/myconf.py
15
- mdbq/myconf/myconf2.py
15
+ mdbq/myconf/myconf_bak.py
16
16
  mdbq/mysql/__init__.py
17
17
  mdbq/mysql/deduplicator.py
18
18
  mdbq/mysql/mysql.py
@@ -1 +0,0 @@
1
- VERSION = '4.0.22'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes