def test_dict_expected(self): assert (check_dict({ 'a': [{ 'b': [] }], 'd': 'e' }, {'a': [['b']]}) == [('a', 0)])
def test_dict_expected(self): assert check_dict({ "a": [{ "b": [] }], "d": "e" }, {"a": [["b"]]}) == [("a", 0)]
def test_exact(self): assert ( check_dict( {"a": [{"b": "c"}], "d": "e"}, {"a": [{"b": "c"}], "d": "e"} ) == [] )
def test_all_wrong(self): assert ( check_dict( {"a": [{"b": "c"}], "d": "e"}, {"q": [{"b": "c"}], "a": [{"z": "x"}], "r": "e"}, ) == [("a", 0, "z"), ("q",), ("r",)] )
def test_list_expected(self): assert (check_dict({ 'a': [{ 'b': [] }], 'd': 'e' }, {'a': [{ 'b': {} }]}) == [('a', 0, 'b')])
def test_child(self): assert (check_dict({ 'a': [{ 'b': 'c' }], 'd': 'e' }, {'a': [{ 'b': 'c' }]}) == [])
def test_list_expected(self): assert check_dict({ "a": [{ "b": [] }], "d": "e" }, {"a": [{ "b": {} }]}) == [("a", 0, "b")]
def test_child(self): assert (check_dict({ "a": [{ "b": "c" }], "d": "e" }, {"a": [{ "b": "c" }]}) == [])
def test_exact(self): assert (check_dict({ 'a': [{ 'b': 'c' }], 'd': 'e' }, { 'a': [{ 'b': 'c' }], 'd': 'e' }) == [])
def test_all_wrong(self): assert (check_dict({ 'a': [{ 'b': 'c' }], 'd': 'e' }, { 'q': [{ 'b': 'c' }], 'a': [{ 'z': 'x' }], 'r': 'e' }) == [('a', 0, 'z'), ('q', ), ('r', )])
def package_revise(context, data_dict): '''Revise a dataset (package) selectively with match, filter and update parameters. You must be authorized to edit the dataset and the groups that it belongs to. :param match: a dict containing "id" or "name" values of the dataset to update, all values provided must match the current dataset values or a ValidationError will be raised. e.g. ``{"name": "my-data", "resources": {["name": "big.csv"]}}`` would abort if the my-data dataset's first resource name is not "big.csv". :type match: dict :param filter: a list of string patterns of fields to remove from the current dataset. e.g. ``"-resources__1"`` would remove the second resource, ``"+title, +resources, -*"`` would remove all fields at the dataset level except title and all resources (default: ``[]``) :type filter: comma-separated string patterns or list of string patterns :param update: a dict with values to update/create after filtering e.g. ``{"resources": [{"description": "file here"}]}`` would update the description for the first resource :type update: dict :param include: a list of string pattern of fields to include in response e.g. ``"-*"`` to return nothing (default: ``[]`` all fields returned) :type include: comma-separated-string patterns or list of string patterns ``match`` and ``update`` parameters may also be passed as "flattened keys", using either the item numeric index or its unique id (with a minimum of 5 characters), e.g. ``update__resource__1f9ab__description="guidebook"`` would set the description of the resource with id starting with "1f9ab" to "guidebook", and ``update__resource__-1__description="guidebook"`` would do the same on the last resource in the dataset. The ``extend`` suffix can also be used on the update parameter to add a new item to a list, e.g. ``update__resources__extend=[{"name": "new resource", "url": "https://example.com"}]`` will add a new resource to the dataset with the provided ``name`` and ``url``. Usage examples: * Change description in dataset, checking for old description:: match={"notes": "old notes", "name": "xyz"} update={"notes": "new notes"} * Identical to above, but using flattened keys:: match__name="xyz" match__notes="old notes" update__notes="new notes" * Replace all fields at dataset level only, keep resources (note: dataset id and type fields can't be deleted) :: match={"id": "1234abc-1420-cbad-1922"} filter=["+resources", "-*"] update={"name": "fresh-start", "title": "Fresh Start"} * Add a new resource (__extend on flattened key):: match={"id": "abc0123-1420-cbad-1922"} update__resources__extend=[{"name": "new resource", "url": "http://example.com"}] * Update a resource by its index:: match={"name": "my-data"} update__resources__0={"name": "new name, first resource"} * Update a resource by its id (provide at least 5 characters):: match={"name": "their-data"} update__resources__19cfad={"description": "right one for sure"} * Replace all fields of a resource:: match={"id": "34a12bc-1420-cbad-1922"} filter=["+resources__1492a__id", "-resources__1492a__*"] update__resources__1492a={"name": "edits here", "url": "http://example.com"} :returns: a dict containing 'package':the updated dataset with fields filtered by include parameter :rtype: dictionary ''' model = context['model'] schema = schema_.package_revise_schema() data, errors = _validate(data_dict, schema, context) if errors: model.Session.rollback() raise ValidationError(errors) name_or_id = ( data['match__'].get('id') or data.get('match', {}).get('id') or data['match__'].get('name') or data.get('match', {}).get('name')) if name_or_id is None: raise ValidationError({'match__id': _('Missing value')}) package_show_context = dict( context, for_update=True) orig = _get_action('package_show')( package_show_context, {'id': name_or_id}) pkg = package_show_context['package'] # side-effect of package_show unmatched = [] if 'match' in data: unmatched.extend(dfunc.check_dict(orig, data['match'])) for k, v in sorted(data['match__'].items()): unmatched.extend(dfunc.check_string_key(orig, k, v)) if unmatched: model.Session.rollback() raise ValidationError([{'match': [ '__'.join(str(p) for p in unm) for unm in unmatched ]}]) if 'filter' in data: orig_id = orig['id'] dfunc.filter_glob_match(orig, data['filter']) orig['id'] = orig_id if 'update' in data: try: dfunc.update_merge_dict(orig, data['update']) except dfunc.DataError as de: model.Session.rollback() raise ValidationError([{'update': [de.error]}]) # update __extend keys before __#__* so that files may be # attached to newly added resources in the same call try: for k, v in sorted( data['update__'].items(), key=lambda s: s[0][-6] if s[0].endswith('extend') else s[0]): dfunc.update_merge_string_key(orig, k, v) except dfunc.DataError as de: model.Session.rollback() raise ValidationError([{k: [de.error]}]) _check_access('package_revise', context, {"update": orig}) # future-proof return dict by putting package data under # "package". We will want to return activity info # on update or "nothing changed" status once possible rval = { 'package': _get_action('package_update')( dict(context, package=pkg), orig)} if 'include' in data_dict: dfunc.filter_glob_match(rval, data_dict['include']) return rval
def test_parent(self): assert check_dict({"a": [{"b": "c"}], "d": "e"}, {"d": "e"}) == []