Mercurial > hgrepos > Python > libs > ConfigMix
comparison configmix/__init__.py @ 303:2a2f5b86fe34
Move some important public constants into the .constants sub-module
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Sun, 25 Apr 2021 16:09:00 +0200 |
| parents | 5648e4611383 |
| children | ce7aea9eac4a |
comparison
equal
deleted
inserted
replaced
| 302:063099b188cd | 303:2a2f5b86fe34 |
|---|---|
| 29 import copy | 29 import copy |
| 30 import io | 30 import io |
| 31 import os | 31 import os |
| 32 import re | 32 import re |
| 33 | 33 |
| 34 from .compat import u, u2fs | 34 from .compat import u2fs |
| 35 from .config import Configuration | 35 from .config import Configuration |
| 36 | 36 from . import constants |
| 37 | |
| 38 COMMENTS = [ | |
| 39 u("__comment"), | |
| 40 u("__doc"), | |
| 41 ] | |
| 42 """Prefixes for comment configuration keys that are to be handled as | |
| 43 comments | |
| 44 | |
| 45 """ | |
| 46 | |
| 47 DIR_PREFIX = u("<dir>") | |
| 48 """Prefix for configuration values to read other configuration files from | |
| 49 given directory | |
| 50 | |
| 51 """ | |
| 52 | |
| 53 DEL_VALUE = u("{{::DEL::}}") | |
| 54 """Value for configuration items to signal that the corresponding | |
| 55 key-value is to be deleted when configurations are merged | |
| 56 | |
| 57 """ | |
| 58 | 37 |
| 59 | 38 |
| 60 def load(*files, **kwargs): | 39 def load(*files, **kwargs): |
| 61 """Load the given configuration files, merge them in the given order | 40 """Load the given configuration files, merge them in the given order |
| 62 and return the resulting configuration dictionary. | 41 and return the resulting configuration dictionary. |
| 88 if defaults is None: | 67 if defaults is None: |
| 89 ex = Configuration() | 68 ex = Configuration() |
| 90 else: | 69 else: |
| 91 ex = merge(None, Configuration(defaults)) | 70 ex = merge(None, Configuration(defaults)) |
| 92 for f in files: | 71 for f in files: |
| 93 if f.startswith(DIR_PREFIX): | 72 if f.startswith(constants.DIR_PREFIX): |
| 94 for f2 in _get_configuration_files_from_dir(f[5:]): | 73 for f2 in _get_configuration_files_from_dir(f[5:]): |
| 95 nx = _load_cfg_from_file(f2, ignore_unknown=True, strict=strict) | 74 nx = _load_cfg_from_file(f2, ignore_unknown=True, strict=strict) |
| 96 if nx is not None: | 75 if nx is not None: |
| 97 ex = merge(nx, ex) | 76 ex = merge(nx, ex) |
| 98 else: | 77 else: |
| 115 if defaults is None: | 94 if defaults is None: |
| 116 ex = Configuration() | 95 ex = Configuration() |
| 117 else: | 96 else: |
| 118 ex = safe_merge(None, Configuration(defaults)) | 97 ex = safe_merge(None, Configuration(defaults)) |
| 119 for f in files: | 98 for f in files: |
| 120 if f.startswith(DIR_PREFIX): | 99 if f.startswith(constants.DIR_PREFIX): |
| 121 for f2 in _get_configuration_files_from_dir(f[5:]): | 100 for f2 in _get_configuration_files_from_dir(f[5:]): |
| 122 nx = _load_cfg_from_file(f2, ignore_unknown=True, strict=strict) | 101 nx = _load_cfg_from_file(f2, ignore_unknown=True, strict=strict) |
| 123 if nx is not None: | 102 if nx is not None: |
| 124 ex = safe_merge(nx, ex) | 103 ex = safe_merge(nx, ex) |
| 125 else: | 104 else: |
| 427 **inplace**. | 406 **inplace**. |
| 428 | 407 |
| 429 The configuration in `default` will be changed **inplace** | 408 The configuration in `default` will be changed **inplace** |
| 430 when filtering out comments (which is the default). | 409 when filtering out comments (which is the default). |
| 431 | 410 |
| 432 If a value in `user` is equal to :data:`.DEL_VALUE` | 411 If a value in `user` is equal to :data:`.constants.DEL_VALUE` |
| 433 (``{{::DEL::}}``) the corresponding key will be deleted from the | 412 (``{{::DEL::}}``) the corresponding key will be deleted from the |
| 434 merged output. | 413 merged output. |
| 435 | 414 |
| 436 From http://stackoverflow.com/questions/823196/yaml-merge-in-python | 415 From http://stackoverflow.com/questions/823196/yaml-merge-in-python |
| 437 | 416 |
| 446 if isinstance(user, dict) and isinstance(default, dict): | 425 if isinstance(user, dict) and isinstance(default, dict): |
| 447 for k, v in default.items(): | 426 for k, v in default.items(): |
| 448 if filter_comments and _is_comment(k): | 427 if filter_comments and _is_comment(k): |
| 449 continue | 428 continue |
| 450 if k in user: | 429 if k in user: |
| 451 if user[k] == DEL_VALUE: | 430 if user[k] == constants.DEL_VALUE: |
| 452 # do not copy | 431 # do not copy |
| 453 del user[k] | 432 del user[k] |
| 454 else: | 433 else: |
| 455 user[k] = _merge(user[k], v, filter_comments) | 434 user[k] = _merge(user[k], v, filter_comments) |
| 456 else: | 435 else: |
| 466 if isinstance(user, dict) and isinstance(default, dict): | 445 if isinstance(user, dict) and isinstance(default, dict): |
| 467 for k, v in default.items(): | 446 for k, v in default.items(): |
| 468 if filter_comments and _is_comment(k): | 447 if filter_comments and _is_comment(k): |
| 469 continue | 448 continue |
| 470 if k in user: | 449 if k in user: |
| 471 if user[k] == DEL_VALUE: | 450 if user[k] == constants.DEL_VALUE: |
| 472 # do not copy | 451 # do not copy |
| 473 del user[k] | 452 del user[k] |
| 474 else: | 453 else: |
| 475 user[k] = _merge(user[k], v, filter_comments) | 454 user[k] = _merge(user[k], v, filter_comments) |
| 476 else: | 455 else: |
| 499 if isinstance(user, dict) and isinstance(default, dict): | 478 if isinstance(user, dict) and isinstance(default, dict): |
| 500 for k, v in default.items(): | 479 for k, v in default.items(): |
| 501 if filter_comments and _is_comment(k): | 480 if filter_comments and _is_comment(k): |
| 502 continue | 481 continue |
| 503 if k in user: | 482 if k in user: |
| 504 if user[k] == DEL_VALUE: | 483 if user[k] == constants.DEL_VALUE: |
| 505 # do not copy | 484 # do not copy |
| 506 del user[k] | 485 del user[k] |
| 507 else: | 486 else: |
| 508 user[k] = _safe_merge(user[k], v, filter_comments) | 487 user[k] = _safe_merge(user[k], v, filter_comments) |
| 509 else: | 488 else: |
| 519 if isinstance(user, dict) and isinstance(default, dict): | 498 if isinstance(user, dict) and isinstance(default, dict): |
| 520 for k, v in default.items(): | 499 for k, v in default.items(): |
| 521 if filter_comments and _is_comment(k): | 500 if filter_comments and _is_comment(k): |
| 522 continue | 501 continue |
| 523 if k in user: | 502 if k in user: |
| 524 if user[k] == DEL_VALUE: | 503 if user[k] == constants.DEL_VALUE: |
| 525 # do not copy | 504 # do not copy |
| 526 del user[k] | 505 del user[k] |
| 527 else: | 506 else: |
| 528 user[k] = _safe_merge(user[k], v, filter_comments) | 507 user[k] = _safe_merge(user[k], v, filter_comments) |
| 529 else: | 508 else: |
| 533 | 512 |
| 534 def _filter_comments(d): | 513 def _filter_comments(d): |
| 535 """Recursively filter comments keys in the dict `d`. | 514 """Recursively filter comments keys in the dict `d`. |
| 536 | 515 |
| 537 Comment keys are keys that start with any of the items in | 516 Comment keys are keys that start with any of the items in |
| 538 :data:`.COMMENTS`. | 517 :data:`.constants.COMMENTS`. |
| 539 | 518 |
| 540 """ | 519 """ |
| 541 if not isinstance(d, dict): | 520 if not isinstance(d, dict): |
| 542 return | 521 return |
| 543 # use a copy of the keys because we change `d` while iterating | 522 # use a copy of the keys because we change `d` while iterating |
| 548 if isinstance(d[k], dict): | 527 if isinstance(d[k], dict): |
| 549 _filter_comments(d[k]) | 528 _filter_comments(d[k]) |
| 550 | 529 |
| 551 | 530 |
| 552 def _is_comment(k): | 531 def _is_comment(k): |
| 553 for i in COMMENTS: | 532 for i in constants.COMMENTS: |
| 554 try: | 533 try: |
| 555 if k.startswith(i): | 534 if k.startswith(i): |
| 556 return True | 535 return True |
| 557 except AttributeError: | 536 except AttributeError: |
| 558 # non-string key | 537 # non-string key |
| 561 | 540 |
| 562 | 541 |
| 563 def _filter_deletions(d): | 542 def _filter_deletions(d): |
| 564 """Recursively filter deletions in the dict `d`. | 543 """Recursively filter deletions in the dict `d`. |
| 565 | 544 |
| 566 Deletions have values that equal :data:`.DEL_VALUE`. | 545 Deletions have values that equal :data:`.constants.DEL_VALUE`. |
| 567 | 546 |
| 568 """ | 547 """ |
| 569 if not isinstance(d, dict): | 548 if not isinstance(d, dict): |
| 570 return | 549 return |
| 571 # use a copy of the items because we change `d` while iterating | 550 # use a copy of the items because we change `d` while iterating |
| 572 for k, v in list(d.items()): | 551 for k, v in list(d.items()): |
| 573 if v == DEL_VALUE: | 552 if v == constants.DEL_VALUE: |
| 574 del d[k] | 553 del d[k] |
| 575 else: | 554 else: |
| 576 if isinstance(d[k], dict): | 555 if isinstance(d[k], dict): |
| 577 _filter_deletions(d[k]) | 556 _filter_deletions(d[k]) |
| 578 | 557 |
