5858from enum import Enum , Flag
5959import os
6060from .config_pb2 import ConfigProto
61- from .types import Error , MIME , ZMQAddress , PyExpr , PyCode , PyCallable , _decompose
61+ from .types import Error , MIME , ZMQAddress , PyExpr , PyCode , PyCallable
6262from .strconv import get_convertor , convert_to_str , Convertor
6363
6464PROTO_CONFIG = 'firebird.base.ConfigProto'
@@ -84,6 +84,49 @@ def create_config(_cls: Type[Config], name: str) -> Config: # pragma: no cover
8484 """
8585 return _cls (name )
8686
87+ # Next two functions are copied from stdlib enum module, as they were removed in Python 3.11
88+
89+ def _decompose (flag , value ):
90+ """
91+ Extract all members from the value.
92+ """
93+ # _decompose is only called if the value is not named
94+ not_covered = value
95+ negative = value < 0
96+ # issue29167: wrap accesses to _value2member_map_ in a list to avoid race
97+ # conditions between iterating over it and having more pseudo-
98+ # members added to it
99+ if negative :
100+ # only check for named flags
101+ flags_to_check = [
102+ (m , v )
103+ for v , m in list (flag ._value2member_map_ .items ())
104+ if m .name is not None
105+ ]
106+ else :
107+ # check for named flags and powers-of-two flags
108+ flags_to_check = [
109+ (m , v )
110+ for v , m in list (flag ._value2member_map_ .items ())
111+ if m .name is not None or _power_of_two (v )
112+ ]
113+ members = []
114+ for member , member_value in flags_to_check :
115+ if member_value and member_value & value == member_value :
116+ members .append (member )
117+ not_covered &= ~ member_value
118+ if not members and value in flag ._value2member_map_ :
119+ members .append (flag ._value2member_map_ [value ])
120+ members .sort (key = lambda m : m ._value_ , reverse = True )
121+ if len (members ) > 1 and members [0 ].value == value :
122+ # we have the breakdown, don't need the value member itself
123+ members .pop (0 )
124+ return members , not_covered
125+
126+ def _power_of_two (value ):
127+ if value < 1 :
128+ return False
129+ return value == 2 ** (value .bit_length () - 1 )
87130
88131class DirectoryScheme :
89132 """Class that provide paths to typically used application directories.
@@ -413,26 +456,30 @@ def _check_value(self, value: T) -> None:
413456 f" not '{ type (value ).__name__ } '" )
414457 def _get_value_description (self ) -> str :
415458 return f'{ self .datatype .__name__ } \n '
416- def _get_config_lines (self ) -> List [str ]:
459+ def _get_config_lines (self , plain : bool = False ) -> List [str ]:
417460 """Returns list of strings containing text lines suitable for use in configuration
418461 file processed with `~configparser.ConfigParser`.
419462
420463 Text lines with configuration start with comment marker `;` and end with newline.
464+
465+ Arguments:
466+ plain: When True, it outputs only the option value. When False, it includes also
467+ option description and other helpful information.
421468
422469 Note:
423470 This function is intended for internal use. To get string describing current
424471 configuration that is suitable for configuration files, use `get_config` method.
425472 """
426- hdr = f"{ self .name } [{ self .datatype .__name__ } ][{ 'REQUIRED' if self .required else 'optional' } ]"
427473 lines = []
428- if self .required :
429- lines .append ("; REQUIRED option.\n " )
430- for line in self .description .strip ().splitlines ():
431- lines .append (f"; { line } \n " )
432- first = True
433- for line in self ._get_value_description ().splitlines ():
434- lines .append (f"; { 'Type: ' if first else '' } { line } \n " )
435- first = False
474+ if not plain :
475+ if self .required :
476+ lines .append ("; REQUIRED option.\n " )
477+ for line in self .description .strip ().splitlines ():
478+ lines .append (f"; { line } \n " )
479+ first = True
480+ for line in self ._get_value_description ().splitlines ():
481+ lines .append (f"; { 'Type: ' if first else '' } { line } \n " )
482+ first = False
436483 value = self .get_value ()
437484 nodef = ';' if value == self .default else ''
438485 value = '<UNDEFINED>' if value is None else self .get_formatted ()
@@ -467,11 +514,15 @@ def validate(self) -> None:
467514 """
468515 if self .required and self .get_value () is None :
469516 raise Error (f"Missing value for required option '{ self .name } '" )
470- def get_config (self ) -> str :
517+ def get_config (self , * , plain : bool = False ) -> str :
471518 """Returns string containing text lines suitable for use in configuration file
472519 processed with `~configparser.ConfigParser`.
520+
521+ Arguments:
522+ plain: When True, it outputs only the option value. When False, it includes also
523+ option description and other helpful information.
473524 """
474- return '' .join (self ._get_config_lines ())
525+ return '' .join (self ._get_config_lines (plain = plain ))
475526 def has_value (self ) -> bool :
476527 """Returns True if option value is not None.
477528 """
@@ -585,18 +636,25 @@ def get_description(self) -> str:
585636 Note: If description is not provided on instance creation, class doc string.
586637 """
587638 return '' if self ._description is None else self ._description
588- def get_config (self ) -> str :
639+ def get_config (self , * , plain : bool = False ) -> str :
589640 """Returns string containing text lines suitable for use in configuration file
590641 processed with `~configparser.ConfigParser`.
642+
643+ Arguments:
644+ plain: When True, it outputs only the option values. When False, it includes also
645+ option descriptions and other helpful information.
591646 """
592647 lines = [f'[{ self .name } ]\n ' , ';\n ' ]
593- for line in self .get_description ().strip ().splitlines ():
594- lines .append (f"; { line } \n " )
648+ if not plain :
649+ for line in self .get_description ().strip ().splitlines ():
650+ lines .append (f"; { line } \n " )
595651 for option in self .options :
596- lines .append ('\n ' )
597- lines .append (option .get_config ())
652+ if not plain :
653+ lines .append ('\n ' )
654+ lines .append (option .get_config (plain = plain ))
598655 for config in self .configs :
599- lines .append ('\n ' )
656+ if not plain :
657+ lines .append ('\n ' )
600658 lines .append (config .get_config ())
601659 return '' .join (lines )
602660 def load_config (self , config : ConfigParser , section : str = None ) -> None :
0 commit comments