def create(self, key, data): """Create a new entity. Create a new entity with the given key and the given data. key (unicode): the key with which the entity will be later accessed data (dict): the properties of the entity raise (InvalidKey): if key isn't a unicode or if an entity with the same key is already present in the store. raise (InvalidData): if data cannot be parsed, if it's missing some properties or if properties are of the wrong type. """ if not isinstance(key, unicode) or key in self._store: raise InvalidKey("Key already in store.") # create entity with LOCK: item = self._entity() item.set(data) if not item.consistent(): raise InvalidData("Inconsistent data") item.key = key self._store[key] = item # notify callbacks for callback in self._create_callbacks: callback(key, item) # reflect changes on the persistent storage try: path = os.path.join(self._path, key + '.json') with io.open(path, 'wb') as rec: json.dump(self._store[key].get(), rec, encoding='utf-8') except IOError: logger.error("I/O error occured while creating entity", exc_info=True)
def merge_list(self, data_dict): """Merge a list of entities. Take a dictionary of entites and, for each of them: - if it's not present in the store, create it - if it's present, update it data_dict (dict): the dictionary of entities raise (InvalidData) if data cannot be parsed, if an entity is missing some properties or if properties are of the wrong type. """ with LOCK: if not isinstance(data_dict, dict): raise InvalidData("Not a dictionary") item_dict = dict() for key, value in iteritems(data_dict): try: # FIXME We should allow keys to be arbitrary unicode # strings, so this just needs to be a non-empty check. if not re.match('[A-Za-z0-9_]+', key): raise InvalidData("Invalid key") item = self._entity() item.set(value) if not item.consistent(self._all_stores): raise InvalidData("Inconsistent data") item.key = key item_dict[key] = item except InvalidData as exc: exc.message = "[entity %s] %s" % (key, exc) exc.args = exc.message, raise exc for key, value in iteritems(item_dict): is_new = key not in self._store old_value = self._store.get(key) # insert entity self._store[key] = value # notify callbacks self._update_timestamp() if is_new: for callback in self._create_callbacks: callback(self.timestamp, key, value) else: for callback in self._update_callbacks: callback(self.timestamp, key, old_value, value) # reflect changes on the persistent storage try: path = os.path.join(self._path, key + '.json') if PY3: with io.open(path, 'wt', encoding="utf-8") as rec: json.dump(value.get(), rec) else: with io.open(path, 'wb') as rec: json.dump(value.get(), rec) except IOError: logger.error( "I/O error occured while merging entity lists", exc_info=True)
def merge_list(self, data, confirm=None): """Merge a list of entities. Take a dictionary of entites and, for each of them: - if it's not present in the store, create it - if it's present, update it data (str): the dictionary of entities (a dict encoded in JSON) confirm (callable): action to be performed as soon as we're sure that the action won't fail (in particular, before notifying the callbacks). Raise InvalidData if data cannot be parsed, if an entity is missing some properties or if properties are of the wrong type. """ try: data_dict = json.loads(data) assert type(data_dict) is dict, "Not a dictionary" item_dict = dict() for key, value in data_dict.iteritems(): try: # FIXME We should allow keys to be arbitrary unicode # strings, so this just needs to be a non-empty check. if not re.match("[A-Za-z0-9_]+", key): raise InvalidData('Invalid key') item = self._entity() item.set(value) if not item.consistent(): raise InvalidData('Inconsistent data') item.key = key item_dict[key] = item except InvalidData as exc: exc.message = '[entity %s] %s' % (key, exc) exc.args = exc.message, raise exc except ValueError: raise InvalidData('Invalid JSON') except AssertionError as message: raise InvalidData(str(message)) # confirm the operation if confirm is not None: confirm() for key, value in item_dict.iteritems(): is_new = key not in self._store # insert entity self._store[key] = value # notify callbacks if is_new: for callback in self._create_callbacks: callback(key) else: for callback in self._update_callbacks: callback(key) # reflect changes on the persistent storage try: with open(os.path.join(self._path, key + '.json'), 'w') as rec: rec.write(json.dumps(value.dump())) except IOError: logger.error("IOError occured", exc_info=True)