Package: pulpo-config
pulpo-configOverviewTheConfigclass provides a robust and flexible way to manage configuration settings in Python applications. It offers a simple interface to load, retrieve, and set configuration parameters, making it ideal for projects that require dynamic configuration handling.Key FeaturesEasy InitializationInitialize with a dictionary of options or a JSON file.Automatically loads options from a file if a file path is provided.Flexible Option RetrievalRetrieve configuration values with support for nested keys.Environment variable substitution for values starting with$ENV.Command-Line Argument ProcessingSeamlessly integrates withargparseto update configurations from command-line arguments.Accepts arguments as a dictionary orargparse.Namespaceobject.JSON and String RepresentationConvert configurations to a JSON string or a standard string representation for easy debugging and logging.Specialized Value RetrievalGet configuration values as boolean or integer types withgetAsBoolandgetAsInt.Handles type conversion and validation internally.Dynamic Configuration SettingSet configuration values with support for nested keys.Automatically creates intermediate dictionaries if needed.BenefitsFlexibility: Easily manage configurations with varying levels of complexity.Simplicity: Streamline configuration management without extensive boilerplate code.Compatibility: Works seamlessly with common Python libraries likeargparse.Extensibility: Customize and extend for more complex use cases or specific project needs.Basic Usagefrompulpo_configimportConfig# Can load values manually through a dictionary..config=Config(options={"database":{"host":"localhost","port":3306}})# Or can load values manually..config.set("api_key","your-api-key")config.set('database.host','localhost')# Or can load options from a JSON config fileconfig=Config(json_file_path="config.json")# Or can load from command line parametersimportargparseparser=argparse.ArgumentParser()parser.add_argument('--debug_mode',type=str)config.process_args(parser)# Retrieve a simple configuration valueapi_key=config.get("api_key")# Retrieve a simple configuration valueis_debug_mode=config.getAsBool("debug_mode")# Retrieve a nested configuration valuedb_host=config.get("database.host")APITerms: Config vs OptionsIn this library, I use the following terms:config: higher level class that offers ability toset/get, but also ability to load from a variety of sources or convenience methodsoptions: low level dictionary of key-value pairs, used to initializeConfig.  Anoptionsdictionary is used as the internal data store for the Config implementationConstructorConfigcan be initialized with a dictionary or json formatted config fileConfig(options: dict = None, json_file_path: str = None)With no parameters, will create aConfigwith no valuesIfoptionssupplied, will initialize with the supplied key-value pairs.  Note that this does support nest key-value structures.What ifoptionsis modified after being used to initializeConfig?  Readhere.Ifjson_file_pathwill load values from json formatted config fileLoad from sourcesThere are a set of methods to load from others sources.  Each for these will copy key-value pairs from parameter toConfigand return the instance ofConfig(to support chain calls).  For example:config=Config().fromOptions(options).fromKeyValue('k','v').fromJsonFile('config.json')fromOptions(self, options: dict = None)loadConfigwith the supplied key-value pairs.  Note that this does support nest key-value structures.fromKeyValue(self, key: str, value: typing.Any)loadConfigwith the supplied key-value pair.fromJsonFile(self, file_path: str)loadConfigwith the content from the supplied json filefromYamlFile(self, file_path: str)loadConfigwith the content from the supplied yaml filefromArgumentParser(self, args: dict)loadConfigwith command line arguments.argscan be eitherargparserorargparser.namepspace(the output fromargparser.parse())Load from sourcesThere are a set of methods to load from others sources.  Each for these will copy key-value pairs from parameter toConfigand return the instance ofConfig(to support chain calls).  For example:config=Config().fromOptions(options).fromKeyValue('k','v').fromJsonFile('config.json')fromOptions(self, options: dict = None)loadConfigwith the supplied key-value pairs.  Note that this does support nest key-value structures.fromKeyValue(self, key: str, value: typing.Any)loadConfigwith the supplied key-value pair.fromKeyValueList(self, key_value_list)loadConfigwith supplied key-value pairs.fromJsonFile(self, file_path: str)loadConfigwith the content from the supplied json file.fromYamlFile(self, file_path: str)loadConfigwith the content from the supplied yaml file.fromArgumentParser(self, args: dict)loadConfigwith command line arguments.argscan be eitherargparserorargparser.namepspace(the output fromargparser.parse())process_argsPassing a standardargparserorargparser.namepspacewill integrate command line params into the config valuesprocess_args(self, args: dict)Setset(key: str, value: typing.Any)Will set key=valuevaluecan be of any type, and would be returned as setTo set a nested value (such as if database option has child option of host), use a.:config.set('database.host', 'localhost')If nested value parent(s) (such as database in the above example) does not exist, those parent(s) will be created.Getget(key: str, default_value: typing.Any = None)Will return the value associated the keyIf there is not a set value, the thedefault_valueis returnedTo get a nested value, use a.:config.get('database.host')There are also specialized get methods to cast values to specific typesgetAsBool(self, key: str, default_value: typing.Any = None) -> boolgetAsInt(self, key: str, default_value: int = None) -> intKeys, Values, Iteratorkeys: returns a list of keys.  If the options are nested, will return in dot notation (i.e.['parent.k1', 'parent.k2'])values: returns a dictionary with all key-value pairs.If the options are nested, will return in dot notation (i.e.{'parent.k1': 'v1', 'parent.k2': 'v2'})__iter__: iterates over the list of keys (for key in config)More Usage PatternsLoading from dictionaryUsing fromOptionsfrompulpo_configimportConfigoptions={"api_key":"your-api-key","database":{"host":"localhost","port":3306}}config=Config().fromOptions(options)api_key=config.get("api_key")host=config.get("database.host")Using constructorfrompulpo_configimportConfigconfig=Config(options={"api_key":"your-api-key","database":{"host":"localhost","port":3306}}api_key=config.get("api_key")host=config.get("database.host")Manually setting configfrompulpo_configimportConfigconfig=Config()config.set("api_key","your-api-key")config.set("database.host","localhost")config.set("database.port",3306)api_key=config.get("api_key")host=config.get("database.host")Loading from json config fileMost use cases will utilize a config file to store options.  Below is a sample config{"api_key":"your-api-key","database":{"host":"localhost","port":3306}}Load this config file namedconfig.jsonusing the following:from pulpo_config import Config
config = Config().fromJsonFile(file_path='config.json')
api_key = config.get("api_key")
host = config.get("database.host")Loading from command line parametersIn a scenario in which you are using commandline params withargparser, use the following:from pulpo_config import Config
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--api_key', type=str)
config = Config().fromArgumentParser(parser)
api_key = config.get("api_key")Get bool valuesThegetAsBoolwill cast the value to a bool.  For this purpose, the following are consideredtrue:[True, 'TRUE', 'T', '1', 1](case-insensitive)if config.getAsBool("enable_feature_x"):
   # do stuffGet in valuesThegetAsIntwill cast the value to an int.port = config.getAsInt("database.host")Extending the Config classFor many application, I prefer to create an application-specific config class, extending from the provided config class.  Example:classMyApplicationConfig(Config):def__init__(self,options:dict=None,json_file_path:str=None):super().__init__(options=options,json_file_path=json_file_path)@propertydefapi_key(self:Config)->str:returnself.get('api_key')@propertydefdebug_mode(self:Config)->str:returnself.getAsBool('debug_mode',False)InstallationPulpo-config is avaiable on PyPi:https://pypi.org/project/pulpo-config/Install usingpip install pulpo-config