def from_conf(cls, path=None, **overrides): '''Initialize instance from YAML configuration file, writing updates (only to keys, specified by "conf_update_keys") back to it.''' from skydrive import portalocker import yaml if path is None: path = cls.conf_path_default log.debug('Using default state-file path: {}'.format(path)) path = os.path.expanduser(path) with open(path) as src: portalocker.lock(src, portalocker.LOCK_SH) #conf = yaml.load("client:\n id: 000000004C0F20A9\n secret: HgkEDnsuysRqhpe3s3vyvznzrMOlTaCo\n") conf = yaml.load(src) portalocker.unlock(src) conf.setdefault('conf_save', path) conf_cls = dict() for ns, keys in cls.conf_update_keys.viewitems(): for k in keys: try: v = conf.get(ns, dict()).get(k) except AttributeError: if not cls.conf_raise_structure_errors: raise raise KeyError('Unable to get value for configuration parameter' ' "{k}" in section "{ns}", check configuration file (path: {path}) syntax' ' near the aforementioned section/value.'.format(ns=ns, k=k, path=path)) if v is not None: conf_cls['{}_{}'.format(ns, k)] = conf[ns][k] conf_cls.update(overrides) self = cls(**conf_cls) self.conf_save = conf['conf_save'] return self
def from_conf(cls, path=None, **overrides): '''Initialize instance from YAML configuration file, writing updates (only to keys, specified by "conf_update_keys") back to it.''' from skydrive import portalocker import yaml if path is None: path = cls.conf_path_default log.debug('Using default state-file path: {}'.format(path)) path = os.path.expanduser(path) with open(path) as src: portalocker.lock(src, portalocker.LOCK_SH) conf = yaml.load(src.read()) portalocker.unlock(src) conf.setdefault('conf_save', path) conf_cls = dict() for ns, keys in cls.conf_update_keys.viewitems(): for k in keys: try: v = conf.get(ns, dict()).get(k) except AttributeError: if not cls.conf_raise_structure_errors: raise raise KeyError( 'Unable to get value for configuration parameter' ' "{k}" in section "{ns}", check configuration file (path: {path}) syntax' ' near the aforementioned section/value.'.format( ns=ns, k=k, path=path)) if v is not None: conf_cls['{}_{}'.format(ns, k)] = conf[ns][k] conf_cls.update(overrides) self = cls(**conf_cls) self.conf_save = conf['conf_save'] return self
def sync(self): if not self.conf_save: conf_updated = False conf = self.conf for ns, keys in self.conf_update_keys.viewitems(): for k in keys: v = getattr(self, '{}_{}'.format(ns, k), None) if isinstance(v, unicode): v = v.encode('utf-8') if v != conf.get(ns, dict()).get(k): # log.debug( # 'Different val ({}.{}): {!r} != {!r}'\ # .format(ns, k, v, conf.get(ns, dict()).get(k)) ) conf.setdefault(ns, dict())[k] = v conf_updated = True if conf_updated: self.conf = conf return conf from skydrive import portalocker import yaml retry = False with open(self.conf_save, 'r+') as src: portalocker.lock(src, portalocker.LOCK_SH) conf_raw = src.read() conf = yaml.load(io.BytesIO(conf_raw)) if conf_raw else dict() portalocker.unlock(src) conf_updated = False for ns, keys in self.conf_update_keys.viewitems(): for k in keys: v = getattr(self, '{}_{}'.format(ns, k), None) if isinstance(v, unicode): v = v.encode('utf-8') if v != conf.get(ns, dict()).get(k): # log.debug( # 'Different val ({}.{}): {!r} != {!r}'\ # .format(ns, k, v, conf.get(ns, dict()).get(k)) ) conf.setdefault(ns, dict())[k] = v conf_updated = True if conf_updated: log.debug('Updating configuration file ({})'.format(src.name)) with tempfile.NamedTemporaryFile( prefix='{}.'.format(basename(self.conf_save)), dir=dirname(self.conf_save), delete=False) as tmp: try: portalocker.lock(tmp, portalocker.LOCK_EX) yaml.safe_dump(conf, tmp, default_flow_style=False) tmp.flush() try: os.fchmod(tmp.fileno(), stat.S_IMODE(os.fstat(src.fileno()).st_mode)) except AttributeError: pass portalocker.lock(src, portalocker.LOCK_EX) src.seek(0) if src.read() != conf_raw: retry = True else: # Atomic update try: os.rename(tmp.name, src.name) except WindowsError: pass # Non-atomic update for pids that already have fd to old file, # but (presumably) are waiting for the write-lock to be released src.seek(0), tmp.seek(0) src.truncate() src.write(tmp.read()) src.flush() finally: portalocker.unlock(tmp) portalocker.unlock(src) try: os.unlink(tmp.name) except OSError: pass if retry: log.debug(( 'Configuration file ({}) was changed' ' during merge, restarting merge' ).format(self.conf_save)) return self.sync()
def sync(self): if not self.conf_save: conf_updated = False conf = self.conf for ns, keys in self.conf_update_keys.viewitems(): for k in keys: v = getattr(self, '{}_{}'.format(ns, k), None) if isinstance(v, unicode): v = v.encode('utf-8') if v != conf.get(ns, dict()).get(k): # log.debug( # 'Different val ({}.{}): {!r} != {!r}'\ # .format(ns, k, v, conf.get(ns, dict()).get(k)) ) conf.setdefault(ns, dict())[k] = v conf_updated = True if conf_updated: self.conf = conf return conf from skydrive import portalocker import yaml retry = False with open(self.conf_save, 'r+') as src: portalocker.lock(src, portalocker.LOCK_SH) conf_raw = src.read() conf = yaml.load(io.BytesIO(conf_raw)) if conf_raw else dict() portalocker.unlock(src) conf_updated = False for ns, keys in self.conf_update_keys.viewitems(): for k in keys: v = getattr(self, '{}_{}'.format(ns, k), None) if isinstance(v, unicode): v = v.encode('utf-8') if v != conf.get(ns, dict()).get(k): # log.debug( # 'Different val ({}.{}): {!r} != {!r}'\ # .format(ns, k, v, conf.get(ns, dict()).get(k)) ) conf.setdefault(ns, dict())[k] = v conf_updated = True if conf_updated: log.debug('Updating configuration file ({})'.format(src.name)) with tempfile.NamedTemporaryFile(prefix='{}.'.format( basename(self.conf_save)), dir=dirname(self.conf_save), delete=False) as tmp: try: portalocker.lock(tmp, portalocker.LOCK_EX) yaml.safe_dump(conf, tmp, default_flow_style=False) tmp.flush() try: os.fchmod( tmp.fileno(), stat.S_IMODE(os.fstat(src.fileno()).st_mode)) except AttributeError: pass portalocker.lock(src, portalocker.LOCK_EX) src.seek(0) if src.read() != conf_raw: retry = True else: # Atomic update try: os.rename(tmp.name, src.name) except WindowsError: pass # Non-atomic update for pids that already have fd to old file, # but (presumably) are waiting for the write-lock to be released src.seek(0), tmp.seek(0) src.truncate() src.write(tmp.read()) src.flush() finally: portalocker.unlock(tmp) portalocker.unlock(src) try: os.unlink(tmp.name) except OSError: pass if retry: log.debug( ('Configuration file ({}) was changed' ' during merge, restarting merge').format(self.conf_save)) return self.sync()