|
From: Fuzzyman <fuz...@vo...> - 2006-03-17 10:57:34
|
Hello Louis, Can you explain to me what this actually does (sorry for my ignorance). You want to create a default config file from a configspec. You want to copy the comments from the configspec *into* the config file when this is done ? You have attempted to do this with walk, but walk *doesn't* honour the order of the configspec, so you have implemented an alternative. Does that cover it all ? If so then I need to fix ``walk`` so that it *does* honour the order. Could I build your functionality into ConfigObj with an optional ``copy_comments`` option to the validate method ? You could then create your default config file by doing : from validate import Validator from configobj import ConfigObj vdt = Validator() cfg = ConfigObj(configspec=filename) cfg.validate(vdt, copy_comments=True) cfg.write() Is there any functionality you are suggesting that I have missed ? Nicola (other users/developers), are you happy for this to be built into ConfigObj, or would it be better as a separate function ? ``__many__`` should be ignored in the configspec - it is only used to validate sections that exist (of which there may be none, one or more). This is what ``validate`` already does. String interpolation should be off, leaving the substitution to be done when values are fetched. Fuzzyman http://www.voidspace.org.uk/python/index.shtml Nicola Larosa wrote: > Hi Louis, sorry for the late answer, this email somehow escaped my > attention for a while. > > Thanks a lot for your contribution, it seems interesting. Michael? > > > Louis Cordier wrote: > >> Hi guys, >> >> Here is a piece of code to generate a 'default' config file >> from the configspec. Basically it copies the comments and >> default values while retaining the sequential order of the >> configspec file. I can think of a few cases where one would >> like to generate a default configfile with proper comments >> for a user (if his/hers' are lost), while keeping them out >> of the configspec file. The comments can list all the valid >> values. >> >> For example how some X servers auto generate a default config >> file. >> >> Anyway this isn't fully complete. I am not too sure how to >> deal with [__many__] or string substitution yet. >> >> I also experimented (ignoring the comments) with using .walk(): >> >> def walker(s, k): >> s.defaults = [] >> >> validator = Validator() >> d = ConfigObj(options={'configspec': 'config.spec'}) >> d.validate(validator) >> d.walk(walker) >> d.filename = 'config.ini' >> d.write() >> >> This for some reason loses the internal order of 'config.spec'. >> >> I think there is probably a few other people that might like this >> functionality. You guys are welcome to add it to configobj.py >> or put it on the webpage. >> >> I suspect this would be a nice way of doing it: >> >> c = ConfigObj(options={'configspec': 'config.spec', >> 'include_comments': True, >> 'retain_order': True, >> 'indent_type': ' '}) >> c.validate(validator) >> c.filename = 'config.ini' >> c.write() >> >> Regards, Louis >> >> >> ------------------------------------------------------------------------ >> >> #!/usr/bin/env python >> >> # >> # author : Louis Cordier <lco...@gm...> >> # description : Testing code for generating a default config file. >> # synopsis : >> # notes : >> # modified : $Id$ >> # >> >> from configobj import ConfigObj, ConfigObjError >> from validate import Validator >> from datetime import datetime >> >> def create_config(configspec): >> """ Create a default config file based on the configspec file. >> >> Load the configspec file as if it was a config file, get the order >> sequence of the sections, keys-value pairs and their comments. >> All configspec values are then interpeted as strings to be ignored. >> Walk the configspec and create a new config file with the default >> values and comments of the configspec. >> >> @note: This is a special case, [__many__] are not yet supported. >> >> @note: ConfigObj.walk() will only work on sections to copy the >> comments, not the complete config object. >> We could transverse the parent()-tree, this feels ugly though. >> >> @note: We could recursively empty all the defaults members and copy >> the comments, but then we loose the configspec sequence though. >> """ >> >> def copy_section(spec_section, source_section, target_section): >> """ Recursive copy sections. >> >> Copy default values from source_section to target_section >> and comments from spec_section to target_section. >> Follow the sequence as specified in spec_section. >> """ >> # Deal with the root section, the config object itself. >> if hasattr(source_section,'initial_comment'): >> target_section.initial_comment = spec_section.initial_comment >> >> # Deal with the root section, the config object itself. >> if hasattr(source_section,'final_comment'): >> target_section.final_comment = spec_section.final_comment >> >> target_section.inline_comments = spec_section.inline_comments >> target_section.comments = spec_section.comments >> >> for key in spec_section.keys(): >> if key in spec_section.sections: >> target_section[key] = {} >> copy_section(spec_section[key], source_section[key], target_section[key]) >> else: >> target_section[key] = source_section[key] >> >> >> try: >> spec = ConfigObj(infile=configspec) >> >> except (IOError), e: >> # The configspec file needs to exist for this to work. >> pass >> >> # Let this function raise configobj.ConfigObjError, >> # in case of a broken configspec. >> >> else: >> try: >> source = ConfigObj(options={'configspec': configspec}) >> >> except (IOError), e: >> # The configspec file needs to exist for this to work. >> pass >> >> # Broken configspec, should have failed earlier already. >> >> else: >> # Now get all the default values. >> # This can only fail if the configspec is broken. >> validator = Validator() >> valid = source.validate(validator) >> >> if valid == True: >> # Create a new config object to be populated. >> target = ConfigObj(options={'configspec': configspec, >> 'indent_type': ' '}) >> >> copy_section(spec, source, target) >> return target >> else: >> raise ConfigObjError, "Bad configspec, '%s'" % (configspec) >> >> # It should ideally never get here. >> return None >> >> >> if __name__ == '__main__': >> >> # Maybe put configspec in the code itself, if config.ini doesn't exist >> # it could write a default file with comments. >> try: >> default_config = create_config('config.spec') >> except (ConfigObjError), e: >> print 'Ooops', e >> else: >> default_config.filename = 'config.ini' >> default_config.initial_comment.insert(0, 'Automatically generated from %s on %sZ\n' % ('config.spec', datetime.utcnow().isoformat())) >> default_config.write() >> >> >> >> ------------------------------------------------------------------------ >> >> # >> # Main config file... >> # >> >> # >> # Server setup >> # >> [server] >> active = boolean(default=True) >> name = string(default=Michael) >> age = float(default=0.0) >> sex = option(m, f, default=m) >> >> >> # >> # Database setup >> # >> [database] >> database = string(default=hydra) >> host = string(default=nostromo.intranet) >> user = string(default=hydra) >> password = string(default=hydra) >> >> # >> # Level 1 Comment >> # >> [[level1]] >> tl1=integer(default=1) >> >> # >> # Edit only if you know what you are doing. >> tl2=integer(default=2) # tl2 inline >> >> [[[test]]] >> test1=integer(default=1) >> test2=integer(default=2) >> >> [[[[sub_test]]]] >> # sub1 >> sub1=integer(default=1) #sub1-inline >> # sub2 >> sub2=integer(default=2) #sub2-inline >> >> # >> # Level 1 footer. >> # >> >> > > > |