def traverse(pkg_func, query='*:*'): client = CkanClient(base_location=HOST, api_key=API_KEY) for page in count(1): results_page = client.package_search(query, search_options={ 'offset': page*PAGE_SIZE, 'limit': PAGE_SIZE}) #pprint(results_page) if not len(results_page.get('results', [])): break for pkg_name in results_page.get('results', []): print "Traversing", pkg_name pkg = client.package_entity_get(pkg_name) ret = pkg_func(client, pkg) if ret is not None: client.package_entity_put(ret, package_name=pkg_name)
def traverse(pkg_func, query='*:*'): client = CkanClient(base_location=HOST, api_key=API_KEY) for page in count(1): results_page = client.package_search(query, search_options={ 'offset': page * PAGE_SIZE, 'limit': PAGE_SIZE }) #pprint(results_page) if not len(results_page.get('results', [])): break for pkg_name in results_page.get('results', []): print "Traversing", pkg_name pkg = client.package_entity_get(pkg_name) ret = pkg_func(client, pkg) if ret is not None: client.package_entity_put(ret, package_name=pkg_name)
def process(self, *av, **kw): ckan = CkanClient(*av, **kw) for dataset, descr in self: _, pkgname = dataset.rsplit("/", 1) pkg = ckan.package_entity_get(pkgname) self.__unmerge__(pkg, self.removals.get(dataset, {})) self.__merge__(pkg, descr) groups = pkg.get("groups", []) self.__fixup__(pkg) ckan.package_entity_put(pkg) self.log_api_result(pkgname, ckan) for groupname in groups: group = ckan.group_entity_get(groupname) pkglist = group.setdefault("packages", []) if pkgname not in pkglist: pkglist.append(pkgname) ckan.group_entity_put(group) self.log_api_result(groupname, ckan) self.flush()
class TestCkanClient(CkanServerCase): @classmethod def setup_class(self): self.pid = self._start_ckan_server() self.test_base_location = 'http://127.0.0.1:5000/api' self._wait_for_url(url=self.test_base_location) self._recreate_ckan_server_testdata(config_path) # this is api key created for tester user by create-test-data in ckan test_api_key = 'tester' test_api_key2 = 'tester2' self.c = CkanClient( base_location=self.test_base_location, api_key=test_api_key, is_verbose=True, ) self.c2 = CkanClient( base_location=self.test_base_location, api_key=test_api_key2, is_verbose=True, ) @classmethod def teardown_class(self): self._stop_ckan_server(self.pid) def delete_relationships(self): res = self.c.package_relationship_register_get('annakarenina') if self.c.last_status == 200: if self.c.last_message: for rel_dict in self.c.last_message: self.c.package_relationship_entity_delete( \ rel_dict['subject'], rel_dict['type'], rel_dict['object']) def test_01_get_locations(self): rest_base = self.test_base_location + '/rest' search_base = self.test_base_location + '/search' url = self.c.get_location('Base') assert url == self.test_base_location, url url = self.c.get_location('Package Register') assert url == rest_base + '/package' url = self.c.get_location('Package Entity', 'myname') assert url == rest_base + '/package/myname' url = self.c.get_location('Package Entity', 'myname', 'relationships') assert url == rest_base + '/package/myname/relationships' url = self.c.get_location('Package Entity', 'myname', 'relationships', 'name2') assert url == rest_base + '/package/myname/relationships/name2' url = self.c.get_location('Package Entity', 'myname', 'child_of', 'name2') assert url == rest_base + '/package/myname/child_of/name2' url = self.c.get_location('Group Register') assert url == rest_base + '/group' url = self.c.get_location('Group Entity', 'myname') assert url == rest_base + '/group/myname' url = self.c.get_location('Tag Register') assert url == rest_base + '/tag' url = self.c.get_location('Tag Entity', 'myname') assert url == rest_base + '/tag/myname' url = self.c.get_location('Tag Entity', 'myname') assert url == rest_base + '/tag/myname' url = self.c.get_location('Package Search') assert url == search_base + '/package' def test_02_get_api_version(self): version = self.c.api_version_get() status = self.c.last_status assert status == 200 body = self.c.last_body assert 'version' in body, body assert int(version) > 0, version def test_03_package_register_get(self): self.c.package_register_get() status = self.c.last_status assert status == 200 body = self.c.last_body assert 'annakarenina' in body, body assert type(self.c.last_message) == list assert 'annakarenina' in self.c.last_message def test_04_package_entity_get(self): # Check registered entity is found. self.c.package_entity_get('annakarenina') status = self.c.last_status assert status == 200, status body = self.c.last_body assert 'annakarenina' in body assert self.c.last_message message = self.c.last_message assert type(message) == dict assert message['name'] == u'annakarenina' assert message['title'] == u'A Novel By Tolstoy' def test_05_package_entity_get_404(self): # Check unregistered entity is not found. assert_raises(CkanApiError, self.c.package_entity_get, 'mycoffeecup') status = self.c.last_status assert status == 404, status @classmethod def _generate_pkg_name(self): pkg_name = 'ckanclienttest' import time timestr = str(time.time()).replace('.', '') pkg_name += timestr return pkg_name def test_06_package_register_post(self): pkg_name = self._generate_pkg_name() # Check package isn't registered. assert_raises(CkanApiError, self.c.package_entity_get, pkg_name) status = self.c.last_status assert status == 404, status # Check registration of new package. package = { 'name': pkg_name, 'url': 'orig_url', 'download_url': 'orig_download_url', 'tags': ['russian', 'newtag'], 'extras': { 'genre': 'thriller', 'format': 'ebook' }, } self.c.package_register_post(package) status = self.c.last_status assert status == 201, status # Check package is registered. self.c.package_entity_get(pkg_name) status = self.c.last_status assert status == 200, status message = self.c.last_message assert message assert 'name' in message, repr(message) name = message['name'] assert name == pkg_name url = message['url'] assert url == 'orig_url' download_url = message['download_url'] assert download_url == 'orig_download_url' tags = message['tags'] # order out is not guaranteed assert set(tags) == set(['newtag', 'russian']), tags extras = message['extras'] assert extras == package['extras'] def test_07_package_entity_put(self): # Register new package. pkg_name_test_07 = self._generate_pkg_name() package = { 'name': pkg_name_test_07, 'url': 'orig_url', 'download_url': 'orig_download_url', 'tags': ['russian'], } self.c.package_register_post(package) status = self.c.last_status assert status == 201, status # Check update of existing package. mytag = 'mytag' + pkg_name_test_07 package = { 'name': pkg_name_test_07, 'url': 'new_url', 'download_url': 'new_download_url', 'tags': ['russian', 'tolstoy', mytag], 'extras': { 'genre': 'thriller', 'format': 'ebook' }, } self.c.package_entity_put(package) status = self.c.last_status assert status == 200 # Check package is updated. self.c.package_entity_get(pkg_name_test_07) status = self.c.last_status assert status == 200, status message = self.c.last_message name = message['name'] assert name == pkg_name_test_07 url = message['url'] assert url == 'new_url' download_url = message['download_url'] assert download_url == 'new_download_url' tags = message['tags'] # order out is not guaranteed assert set(tags) == set(['russian', 'tolstoy', mytag]), tags extras = message['extras'] assert extras == package['extras'] def test_08_package_entity_delete(self): # create a package to be deleted pkg_name = self._generate_pkg_name() self.c.package_register_post({'name': pkg_name}) status = self.c.last_status assert status == 201, status # check it is readable self.c.package_entity_get(pkg_name) assert self.c.last_status == 200, self.c.last_status # delete it self.c.package_entity_delete(pkg_name) # see it is not readable by another user assert_raises(CkanApiError, self.c2.package_entity_get, pkg_name) assert self.c2.last_status == 403, self.c.last_status # see it is still readable by the author (therefore pkg admin) self.c.package_entity_get(pkg_name) assert self.c.last_status == 200, self.c.last_status def test_09_tag_register_get(self): self.c.tag_register_get() status = self.c.last_status assert status == 200 body = self.c.last_body assert 'russian' in body assert type(self.c.last_message) == list assert 'russian' in self.c.last_message def test_10_pkg_search_basic(self): res = self.c.package_search('Novel') status = self.c.last_status assert status == 200, status assert_equal(list(res['results']), [u'annakarenina']) assert_equal(res['count'], 1) def test_10_pkg_search_paged(self): res = self.c.package_search('russian', search_options={'limit': 1}) status = self.c.last_status assert status == 200, status all_results = list(res['results']) assert set(all_results) >= set([u'annakarenina', u'warandpeace' ]), all_results assert res['count'] >= 2, '%r %r' % (res, all_results) def test_10_pkg_search_options(self): res = self.c.package_search(None, search_options={'groups': 'roger'}) status = self.c.last_status assert status == 200, status assert_equal(list(res['results']), [u'annakarenina']) assert_equal(res['count'], 1) def test_10_pkg_search_options_all_fields(self): res = self.c.package_search(None, search_options={ 'groups': 'roger', 'all_fields': True }) status = self.c.last_status assert status == 200, status assert_equal(res['count'], 1) assert_equal(list(res['results'])[0]['name'], u'annakarenina') def test_11_package_relationship_post(self): res = self.c.package_relationship_register_get('annakarenina') assert self.c.last_status == 200, self.c.last_status assert not self.c.last_message, self.c.last_body # create relationship res = self.c.package_relationship_entity_post('annakarenina', 'child_of', 'warandpeace', 'some comment') try: assert self.c.last_status == 201, self.c.last_status finally: self.delete_relationships() def test_12_package_relationship_get(self): # create relationship res = self.c.package_relationship_entity_post('annakarenina', 'child_of', 'warandpeace', 'some comment') # read relationship try: res = self.c.package_relationship_register_get('annakarenina') assert self.c.last_status == 200, self.c.last_status rels = self.c.last_message assert len(rels) == 1, rels assert rels[0]['subject'] == 'annakarenina', rels[0] assert rels[0]['object'] == 'warandpeace', rels[0] assert rels[0]['type'] == 'child_of', rels[0] assert rels[0]['comment'] == 'some comment', rels[0] finally: self.delete_relationships() def test_13_package_relationship_put(self): # create relationship res = self.c.package_relationship_entity_post('annakarenina', 'child_of', 'warandpeace', 'some comment') # update relationship try: res = self.c.package_relationship_entity_put( 'annakarenina', 'child_of', 'warandpeace', 'new comment') assert self.c.last_status == 200, self.c.last_status # read relationship res = self.c.package_relationship_register_get('annakarenina') assert self.c.last_status == 200, self.c.last_status rels = self.c.last_message assert len(rels) == 1, rels assert rels[0]['comment'] == 'new comment', rels[0] finally: self.delete_relationships() def test_14_package_relationship_delete(self): # create relationship res = self.c.package_relationship_entity_post('annakarenina', 'child_of', 'warandpeace', 'some comment') try: self.c.package_relationship_entity_delete('annakarenina', 'child_of', 'warandpeace') # read relationship gives 404 assert_raises(CkanApiError, self.c.package_relationship_register_get, 'annakarenina', 'child_of', 'warandpeace') assert self.c.last_status == 404, self.c.last_status # and register of relationships is blank res = self.c.package_relationship_register_get( 'annakarenina', 'relationships', 'warandpeace') assert self.c.last_status == 200, self.c.last_status assert not res, res finally: self.delete_relationships() def test_15_package_edit_form_get(self): try: import ckanext.dgu except exceptions.ImportError, e: raise SkipTest( 'Need dgu_form_api plugin (from ckanext-dgu) installed to test form api client.' ) if 'dgu_form_api' not in config.get('ckan.plugins', ''): raise SkipTest( 'Need dgu_form_api plugin (from ckanext-dgu) enabled to test form api client.' ) res = self.c.package_edit_form_get('annakarenina') assert self.c.last_status == 200, self.c.last_status assert res, res
class TestCkanClient(CkanServerCase): @classmethod def setup_class(self): self.pid = self._start_ckan_server() self.test_base_location = 'http://127.0.0.1:5000/api' self._wait_for_url(url=self.test_base_location) self._recreate_ckan_server_testdata(config_path) # this is api key created for tester user by create-test-data in ckan test_api_key = 'tester' test_api_key2 = 'tester2' self.c = CkanClient( base_location=self.test_base_location, api_key=test_api_key, is_verbose=True, ) self.c2 = CkanClient( base_location=self.test_base_location, api_key=test_api_key2, is_verbose=True, ) @classmethod def teardown_class(self): self._stop_ckan_server(self.pid) def delete_relationships(self): res = self.c.package_relationship_register_get('annakarenina') if self.c.last_status == 200: if self.c.last_message: for rel_dict in self.c.last_message: self.c.package_relationship_entity_delete( \ rel_dict['subject'], rel_dict['type'], rel_dict['object']) def test_01_get_locations(self): rest_base = self.test_base_location + '/rest' search_base = self.test_base_location + '/search' url = self.c.get_location('Base') assert url == self.test_base_location, url url = self.c.get_location('Package Register') assert url == rest_base + '/package' url = self.c.get_location('Package Entity', 'myname') assert url == rest_base + '/package/myname' url = self.c.get_location('Package Entity', 'myname', 'relationships') assert url == rest_base + '/package/myname/relationships' url = self.c.get_location('Package Entity', 'myname', 'relationships', 'name2') assert url == rest_base + '/package/myname/relationships/name2' url = self.c.get_location('Package Entity', 'myname', 'child_of', 'name2') assert url == rest_base + '/package/myname/child_of/name2' url = self.c.get_location('Group Register') assert url == rest_base + '/group' url = self.c.get_location('Group Entity', 'myname') assert url == rest_base + '/group/myname' url = self.c.get_location('Tag Register') assert url == rest_base + '/tag' url = self.c.get_location('Tag Entity', 'myname') assert url == rest_base + '/tag/myname' url = self.c.get_location('Tag Entity', 'myname') assert url == rest_base + '/tag/myname' url = self.c.get_location('Package Search') assert url == search_base + '/package' def test_02_get_api_version(self): version = self.c.api_version_get() status = self.c.last_status assert status == 200 body = self.c.last_body assert 'version' in body, body assert int(version) > 0, version def test_03_package_register_get(self): self.c.package_register_get() status = self.c.last_status assert status == 200 body = self.c.last_body assert 'annakarenina' in body, body assert type(self.c.last_message) == list assert 'annakarenina' in self.c.last_message def test_04_package_entity_get(self): # Check registered entity is found. self.c.package_entity_get('annakarenina') status = self.c.last_status assert status == 200, status body = self.c.last_body assert 'annakarenina' in body assert self.c.last_message message = self.c.last_message assert type(message) == dict assert message['name'] == u'annakarenina' assert message['title'] == u'A Novel By Tolstoy' def test_05_package_entity_get_404(self): # Check unregistered entity is not found. assert_raises(CkanApiError, self.c.package_entity_get, 'mycoffeecup') status = self.c.last_status assert status == 404, status @classmethod def _generate_pkg_name(self): pkg_name = 'ckanclienttest' import time timestr = str(time.time()).replace('.', '') pkg_name += timestr return pkg_name def test_06_package_register_post(self): pkg_name = self._generate_pkg_name() # Check package isn't registered. assert_raises(CkanApiError, self.c.package_entity_get, pkg_name) status = self.c.last_status assert status == 404, status # Check registration of new package. package = { 'name': pkg_name, 'url': 'orig_url', 'download_url': 'orig_download_url', 'tags': ['russian', 'newtag'], 'extras': {'genre':'thriller', 'format':'ebook'}, } self.c.package_register_post(package) status = self.c.last_status assert status == 201, status # Check package is registered. self.c.package_entity_get(pkg_name) status = self.c.last_status assert status == 200, status message = self.c.last_message assert message assert 'name' in message, repr(message) name = message['name'] assert name == pkg_name url = message['url'] assert url == 'orig_url' download_url = message['download_url'] assert download_url == 'orig_download_url' tags = message['tags'] # order out is not guaranteed assert set(tags) == set(['newtag', 'russian']), tags extras = message['extras'] assert extras == package['extras'] def test_07_package_entity_put(self): # Register new package. pkg_name_test_07 = self._generate_pkg_name() package = { 'name': pkg_name_test_07, 'url': 'orig_url', 'download_url': 'orig_download_url', 'tags': ['russian'], } self.c.package_register_post(package) status = self.c.last_status assert status == 201, status # Check update of existing package. mytag = 'mytag' + pkg_name_test_07 package = { 'name': pkg_name_test_07, 'url': 'new_url', 'download_url': 'new_download_url', 'tags': ['russian', 'tolstoy', mytag], 'extras': {'genre':'thriller', 'format':'ebook'}, } self.c.package_entity_put(package) status = self.c.last_status assert status == 200 # Check package is updated. self.c.package_entity_get(pkg_name_test_07) status = self.c.last_status assert status == 200, status message = self.c.last_message name = message['name'] assert name == pkg_name_test_07 url = message['url'] assert url == 'new_url' download_url = message['download_url'] assert download_url == 'new_download_url' tags = message['tags'] # order out is not guaranteed assert set(tags) == set(['russian', 'tolstoy', mytag]), tags extras = message['extras'] assert extras == package['extras'] def test_08_package_entity_delete(self): # create a package to be deleted pkg_name = self._generate_pkg_name() self.c.package_register_post({'name': pkg_name}) status = self.c.last_status assert status == 201, status # check it is readable self.c.package_entity_get(pkg_name) assert self.c.last_status == 200, self.c.last_status # delete it self.c.package_entity_delete(pkg_name) # see it is not readable by another user assert_raises(CkanApiError, self.c2.package_entity_get, pkg_name) assert self.c2.last_status == 403, self.c.last_status # see it is still readable by the author (therefore pkg admin) self.c.package_entity_get(pkg_name) assert self.c.last_status == 200, self.c.last_status def test_09_tag_register_get(self): self.c.tag_register_get() status = self.c.last_status assert status == 200 body = self.c.last_body assert 'russian' in body assert type(self.c.last_message) == list assert 'russian' in self.c.last_message def test_10_pkg_search_basic(self): res = self.c.package_search('Novel') status = self.c.last_status assert status == 200, status assert_equal(list(res['results']), [u'annakarenina']) assert_equal(res['count'], 1) def test_10_pkg_search_paged(self): res = self.c.package_search('russian', search_options={'limit': 1}) status = self.c.last_status assert status == 200, status all_results = list(res['results']) assert set(all_results) >= set([u'annakarenina', u'warandpeace']), all_results assert res['count'] >= 2, '%r %r' % (res, all_results) def test_10_pkg_search_options(self): res = self.c.package_search(None, search_options={'groups': 'roger'}) status = self.c.last_status assert status == 200, status assert_equal(list(res['results']), [u'annakarenina']) assert_equal(res['count'], 1) def test_10_pkg_search_options_all_fields(self): res = self.c.package_search(None, search_options={'groups': 'roger', 'all_fields': True}) status = self.c.last_status assert status == 200, status assert_equal(res['count'], 1) assert_equal(list(res['results'])[0]['name'], u'annakarenina') def test_11_package_relationship_post(self): res = self.c.package_relationship_register_get('annakarenina') assert self.c.last_status == 200, self.c.last_status assert not self.c.last_message, self.c.last_body # create relationship res = self.c.package_relationship_entity_post('annakarenina', 'child_of', 'warandpeace', 'some comment') try: assert self.c.last_status == 201, self.c.last_status finally: self.delete_relationships() def test_12_package_relationship_get(self): # create relationship res = self.c.package_relationship_entity_post('annakarenina', 'child_of', 'warandpeace', 'some comment') # read relationship try: res = self.c.package_relationship_register_get('annakarenina') assert self.c.last_status == 200, self.c.last_status rels = self.c.last_message assert len(rels) == 1, rels assert rels[0]['subject'] == 'annakarenina', rels[0] assert rels[0]['object'] == 'warandpeace', rels[0] assert rels[0]['type'] == 'child_of', rels[0] assert rels[0]['comment'] == 'some comment', rels[0] finally: self.delete_relationships() def test_13_package_relationship_put(self): # create relationship res = self.c.package_relationship_entity_post('annakarenina', 'child_of', 'warandpeace', 'some comment') # update relationship try: res = self.c.package_relationship_entity_put('annakarenina', 'child_of', 'warandpeace', 'new comment') assert self.c.last_status == 200, self.c.last_status # read relationship res = self.c.package_relationship_register_get('annakarenina') assert self.c.last_status == 200, self.c.last_status rels = self.c.last_message assert len(rels) == 1, rels assert rels[0]['comment'] == 'new comment', rels[0] finally: self.delete_relationships() def test_14_package_relationship_delete(self): # create relationship res = self.c.package_relationship_entity_post('annakarenina', 'child_of', 'warandpeace', 'some comment') try: self.c.package_relationship_entity_delete('annakarenina', 'child_of', 'warandpeace') # read relationship gives 404 assert_raises(CkanApiError, self.c.package_relationship_register_get, 'annakarenina', 'child_of', 'warandpeace') assert self.c.last_status == 404, self.c.last_status # and register of relationships is blank res = self.c.package_relationship_register_get('annakarenina', 'relationships', 'warandpeace') assert self.c.last_status == 200, self.c.last_status assert not res, res finally: self.delete_relationships() def test_15_package_edit_form_get(self): try: import ckanext.dgu except exceptions.ImportError, e: raise SkipTest('Need dgu_form_api plugin (from ckanext-dgu) installed to test form api client.') if 'dgu_form_api' not in config.get('ckan.plugins', ''): raise SkipTest('Need dgu_form_api plugin (from ckanext-dgu) enabled to test form api client.') res = self.c.package_edit_form_get('annakarenina') assert self.c.last_status == 200, self.c.last_status assert res, res
class CkanLoader(object): """ Directs a CKAN service client to put obtained packages on CKAN. """ usage = '''usage: %prog OPTIONS''' def __init__(self): """Sets up options and init the CKAN service client.""" parser = OptionParser(self.usage) self.add_options(parser) (self.options, self.args) = parser.parse_args() self.init_ckanclient() def add_options(self, parser): """Adds options for CKAN serice location and REST API key.""" parser.add_option( '--ckan-api-location', dest='ckan_api_location', default='http://127.0.0.1:5000/api', help="""The location of working CKAN REST API.""") parser.add_option( '--ckan-api-key', dest='ckan_api_key', help="""A valid CKAN REST API key.""") parser.add_option( '--no-create-confirmation', dest='no_create_confimation', action='store_true', help="""Don't prompt for confirmation when registering a new package.""") parser.add_option( '--no-update-confirmation', dest='no_update_confimation', action='store_true', help="""Don't prompt for confirmation when updating a registered package.""") def init_ckanclient(self): """Init the CKAN client from options.""" if not self.options.ckan_api_location: print "Warning: CKAN API location not provided." if not self.options.ckan_api_key: print "Warning: CKAN API key not provided." self.ckanclient = CkanClient( base_location=self.options.ckan_api_location, api_key=self.options.ckan_api_key, ) def run(self): """Obtain packages and put them on CKAN.""" try: self.packages = [] self.obtain_packages() print "Putting %s packages on CKAN running at %s" % (len(self.packages), self.options.ckan_api_location) self.put_packages_on_ckan() except KeyboardInterrupt: print "" print "exiting..." print "" def obtain_packages(self): """Abstract method for obtaining packages.""" raise Exception, "Abstract method not implemented." def put_packages_on_ckan(self): """Uses CKAN client to register (or update) obtained packages.""" # Todo: Fix ckan or ckanclient, so this method isn't so long-winded. print "" sleep(1) for package in self.packages: try: registered_package = self.ckanclient.package_entity_get(package['name']) except CkanApiError: pass if self.ckanclient.last_status == 200: print "Package '%s' is already registered" % package['name'] print "" pprint.pprint(package) print "" if not self.options.no_update_confimation: answer = raw_input("Do you want to update this package with CKAN now? [y/N] ") if not answer or answer.lower()[0] != 'y': print "Skipping '%s' package..." % package['name'] print "" sleep(1) continue print "Updating package..." self.ckanclient.package_entity_put(package) if self.ckanclient.last_status == 200: print "Updated package '%s' OK." % package['name'] sleep(1) elif self.ckanclient.last_status == 403 or '403' in str(self.ckanclient.last_url_error): print "Error: Not authorised. Check your API key." sleep(1) sleep(1) sleep(1) sleep(1) elif self.ckanclient.last_http_error: print "Error: CKAN returned status code %s: %s" % ( self.ckanclient.last_status, self.ckanclient.last_http_error) sleep(1) sleep(1) sleep(1) elif self.ckanclient.last_url_error: print "Error: URL problems: %s" % self.ckanclient.last_url_error sleep(1) sleep(1) sleep(1) else: raise Exception, "Error: CKAN request didn't work at all." elif self.ckanclient.last_status == 404 or '404' in str(self.ckanclient.last_url_error): print "Package '%s' not currently registered" % package['name'] print "" pprint.pprint(package) print "" if not self.options.no_create_confimation: answer = raw_input("Do you want to register this package with CKAN now? [y/N] ") if not answer or answer.lower()[0] != 'y': print "Skipping '%s' package..." % package['name'] print "" sleep(1) continue print "Registering package..." self.ckanclient.package_register_post(package) if self.ckanclient.last_status in [200, 201]: print "Registered package '%s' OK." % package['name'] sleep(1) elif self.ckanclient.last_status == 403 or '403' in str(self.ckanclient.last_url_error): print "Error: Not authorised. Check your API key." sleep(1) sleep(1) sleep(1) sleep(1) elif self.ckanclient.last_http_error: print "Error: CKAN returned status code %s: %s" % ( self.ckanclient.last_status, self.ckanclient.last_http_error) sleep(1) sleep(1) sleep(1) elif self.ckanclient.last_url_error: print "Error: URL problems: %s" % self.ckanclient.last_url_error sleep(1) sleep(1) sleep(1) else: raise Exception, "Error: CKAN request didn't work at all." elif self.ckanclient.last_http_error: print "Error: CKAN returned status code %s: %s" % ( self.ckanclient.last_status, self.ckanclient.last_http_error) sleep(1) sleep(1) sleep(1) elif self.ckanclient.last_url_error: print "Error: URL problems: %s" % self.ckanclient.last_url_error sleep(1) sleep(1) sleep(1) else: raise Exception, "Error: CKAN request didn't work at all." def create_package(self, name, title='', url='', maintainer='', maintainer_email='', author='', author_email='', notes='', tags=[], extras={}, license_id=None, license=None, resources=[]): """Returns a CKAN REST API package from method arguments.""" if not isinstance(tags, list): raise Exception, "Package tags must be a list: %s" % tags if not isinstance(extras, dict): raise Exception, "Package extras must be a dict: %s" % tags package = {} package['name'] = self.coerce_package_name(name) package['title'] = title package['url'] = url package['notes'] = notes package['maintainer'] = maintainer package['maintainer_email'] = maintainer_email package['author'] = author package['author_email'] = author_email package['tags'] = tags package['extras'] = extras # Pre and post licenses servicization. if license_id != None: package['license_id'] = license_id elif license != None: package['license'] = license package['resources'] = resources return package def coerce_package_name(self, name): """Converts unicode string to valid CKAN package name.""" # Todo: Probably needs to be finished off. name = self.substitute_ascii_equivalents(name) name = name.lower() return name def substitute_ascii_equivalents(self, unicrap): # Method taken from: http://code.activestate.com/recipes/251871/ """This takes a UNICODE string and replaces Latin-1 characters with something equivalent in 7-bit ASCII. It returns a plain ASCII string. This function makes a best effort to convert Latin-1 characters into ASCII equivalents. It does not just strip out the Latin-1 characters. All characters in the standard 7-bit ASCII range are preserved. In the 8th bit range all the Latin-1 accented letters are converted to unaccented equivalents. Most symbol characters are converted to something meaningful. Anything not converted is deleted. """ xlate={0xc0:'A', 0xc1:'A', 0xc2:'A', 0xc3:'A', 0xc4:'A', 0xc5:'A', 0xc6:'Ae', 0xc7:'C', 0xc8:'E', 0xc9:'E', 0xca:'E', 0xcb:'E', 0xcc:'I', 0xcd:'I', 0xce:'I', 0xcf:'I', 0xd0:'Th', 0xd1:'N', 0xd2:'O', 0xd3:'O', 0xd4:'O', 0xd5:'O', 0xd6:'O', 0xd8:'O', 0xd9:'U', 0xda:'U', 0xdb:'U', 0xdc:'U', 0xdd:'Y', 0xde:'th', 0xdf:'ss', 0xe0:'a', 0xe1:'a', 0xe2:'a', 0xe3:'a', 0xe4:'a', 0xe5:'a', 0xe6:'ae', 0xe7:'c', 0xe8:'e', 0xe9:'e', 0xea:'e', 0xeb:'e', 0xec:'i', 0xed:'i', 0xee:'i', 0xef:'i', 0xf0:'th', 0xf1:'n', 0xf2:'o', 0xf3:'o', 0xf4:'o', 0xf5:'o', 0xf6:'o', 0xf8:'o', 0xf9:'u', 0xfa:'u', 0xfb:'u', 0xfc:'u', 0xfd:'y', 0xfe:'th', 0xff:'y', #0xa1:'!', 0xa2:'{cent}', 0xa3:'{pound}', 0xa4:'{currency}', #0xa5:'{yen}', 0xa6:'|', 0xa7:'{section}', 0xa8:'{umlaut}', #0xa9:'{C}', 0xaa:'{^a}', 0xab:'<<', 0xac:'{not}', #0xad:'-', 0xae:'{R}', 0xaf:'_', 0xb0:'{degrees}', #0xb1:'{+/-}', 0xb2:'{^2}', 0xb3:'{^3}', 0xb4:"'", #0xb5:'{micro}', 0xb6:'{paragraph}', 0xb7:'*', 0xb8:'{cedilla}', #0xb9:'{^1}', 0xba:'{^o}', 0xbb:'>>', #0xbc:'{1/4}', 0xbd:'{1/2}', 0xbe:'{3/4}', 0xbf:'?', #0xd7:'*', 0xf7:'/' } r = '' for i in unicrap: if xlate.has_key(ord(i)): r += xlate[ord(i)] elif ord(i) >= 0x80: pass else: r += str(i) return r def create_package_resource(self, url='', format='', hash='', description=''): return { 'url': url, 'format': format, 'hash': hash, 'description': description, }
class Package(csv2rdf.interfaces.AuxilaryInterface): """ Reflects the CKAN package. CKAN package contains one or several CKAN resources Properties: maintainer, package_name, maintainer_email, id, metadata_created, ckan, relationships, metadata_modified, author, author_email, download_url, state, version, license_id, type, resources: [], tags: [], tracking_summary, name, isopen, license, notes_rendered, url, ckan_url, notes, license_title, ratings_average, extras: {geographic_coverage, temporal_coverage-from, temporal_granularity, date_updated, published_via, mandate, precision, geographic_granularity, published_by, taxonomy_url, update_frequency, temporal_coverage-to, date_update_future, date_released}, license_url, ratings_count, title, revision_id ckan - <ckanclient.CkanClient object at 0x972ac8c> """ def __init__(self, package_name): self.name = package_name self.ckan = CkanClient(base_location=csv2rdf.config.config.ckan_api_url, api_key=csv2rdf.config.config.ckan_api_key) self.initialize() def initialize(self): entity = self.ckan.package_entity_get(self.name) self.unpack_object_to_self(entity) def get_metadata(self, dataset=None): if(dataset is None): dataset = self.name dataset_meta = self.cache_metadata_get(dataset) if(not dataset_meta): url = csv2rdf.config.config.ckan_base_url + "/dataset/"+dataset+".rdf" r = requests.get(url) assert r.status_code == requests.codes.ok #is 200? dataset_meta = r.content self.cache_metadata_put(dataset, dataset_meta) return dataset_meta def cache_metadata_get(self, dataset): db = csv2rdf.database.DatabasePlainFiles(csv2rdf.config.config.data_packages_metadata_path) if db.is_exists(dataset): return db.loadDbase(dataset) else: return False def cache_metadata_put(self, dataset, metadata): db = csv2rdf.database.DatabasePlainFiles(csv2rdf.config.config.data_packages_metadata_path) db.saveDbase(dataset, metadata) def download_all_resources(self): """ Overwrites existing files! """ db = csv2rdf.database.DatabasePlainFiles(csv2rdf.config.config.resource_dir) for resource in self.resources: url = resource['url'] filename = self.extract_filename_url(url) try: r = requests.get(url, timeout=self.timeout) db.saveDbaseRaw(filename, r.content) except BaseException as e: print "Could not get the resource " + str(resource['id']) + " ! " + str(e) # # Interface - getters # def get_ckan_url(self): return str(self.ckan_base_url) + '/dataset/' + str(self.name)
class CkanLoader(object): """ Directs a CKAN service client to put obtained packages on CKAN. """ usage = '''usage: %prog OPTIONS''' def __init__(self): """Sets up options and init the CKAN service client.""" parser = OptionParser(self.usage) self.add_options(parser) (self.options, self.args) = parser.parse_args() self.init_ckanclient() def add_options(self, parser): """Adds options for CKAN serice location and REST API key.""" parser.add_option('--ckan-api-location', dest='ckan_api_location', default='http://127.0.0.1:5000/api', help="""The location of working CKAN REST API.""") parser.add_option('--ckan-api-key', dest='ckan_api_key', help="""A valid CKAN REST API key.""") parser.add_option( '--no-create-confirmation', dest='no_create_confimation', action='store_true', help= """Don't prompt for confirmation when registering a new package.""" ) parser.add_option( '--no-update-confirmation', dest='no_update_confimation', action='store_true', help= """Don't prompt for confirmation when updating a registered package.""" ) def init_ckanclient(self): """Init the CKAN client from options.""" if not self.options.ckan_api_location: print "Warning: CKAN API location not provided." if not self.options.ckan_api_key: print "Warning: CKAN API key not provided." self.ckanclient = CkanClient( base_location=self.options.ckan_api_location, api_key=self.options.ckan_api_key, ) def run(self): """Obtain packages and put them on CKAN.""" try: self.packages = [] self.obtain_packages() print "Putting %s packages on CKAN running at %s" % (len( self.packages), self.options.ckan_api_location) self.put_packages_on_ckan() except KeyboardInterrupt: print "" print "exiting..." print "" def obtain_packages(self): """Abstract method for obtaining packages.""" raise Exception, "Abstract method not implemented." def put_packages_on_ckan(self): """Uses CKAN client to register (or update) obtained packages.""" # Todo: Fix ckan or ckanclient, so this method isn't so long-winded. print "" sleep(1) for package in self.packages: try: registered_package = self.ckanclient.package_entity_get( package['name']) except CkanApiError: pass if self.ckanclient.last_status == 200: print "Package '%s' is already registered" % package['name'] print "" pprint.pprint(package) print "" if not self.options.no_update_confimation: answer = raw_input( "Do you want to update this package with CKAN now? [y/N] " ) if not answer or answer.lower()[0] != 'y': print "Skipping '%s' package..." % package['name'] print "" sleep(1) continue print "Updating package..." self.ckanclient.package_entity_put(package) if self.ckanclient.last_status == 200: print "Updated package '%s' OK." % package['name'] sleep(1) elif self.ckanclient.last_status == 403 or '403' in str( self.ckanclient.last_url_error): print "Error: Not authorised. Check your API key." sleep(1) sleep(1) sleep(1) sleep(1) elif self.ckanclient.last_http_error: print "Error: CKAN returned status code %s: %s" % ( self.ckanclient.last_status, self.ckanclient.last_http_error) sleep(1) sleep(1) sleep(1) elif self.ckanclient.last_url_error: print "Error: URL problems: %s" % self.ckanclient.last_url_error sleep(1) sleep(1) sleep(1) else: raise Exception, "Error: CKAN request didn't work at all." elif self.ckanclient.last_status == 404 or '404' in str( self.ckanclient.last_url_error): print "Package '%s' not currently registered" % package['name'] print "" pprint.pprint(package) print "" if not self.options.no_create_confimation: answer = raw_input( "Do you want to register this package with CKAN now? [y/N] " ) if not answer or answer.lower()[0] != 'y': print "Skipping '%s' package..." % package['name'] print "" sleep(1) continue print "Registering package..." self.ckanclient.package_register_post(package) if self.ckanclient.last_status in [200, 201]: print "Registered package '%s' OK." % package['name'] sleep(1) elif self.ckanclient.last_status == 403 or '403' in str( self.ckanclient.last_url_error): print "Error: Not authorised. Check your API key." sleep(1) sleep(1) sleep(1) sleep(1) elif self.ckanclient.last_http_error: print "Error: CKAN returned status code %s: %s" % ( self.ckanclient.last_status, self.ckanclient.last_http_error) sleep(1) sleep(1) sleep(1) elif self.ckanclient.last_url_error: print "Error: URL problems: %s" % self.ckanclient.last_url_error sleep(1) sleep(1) sleep(1) else: raise Exception, "Error: CKAN request didn't work at all." elif self.ckanclient.last_http_error: print "Error: CKAN returned status code %s: %s" % ( self.ckanclient.last_status, self.ckanclient.last_http_error) sleep(1) sleep(1) sleep(1) elif self.ckanclient.last_url_error: print "Error: URL problems: %s" % self.ckanclient.last_url_error sleep(1) sleep(1) sleep(1) else: raise Exception, "Error: CKAN request didn't work at all." def create_package(self, name, title='', url='', maintainer='', maintainer_email='', author='', author_email='', notes='', tags=[], extras={}, license_id=None, license=None, resources=[]): """Returns a CKAN REST API package from method arguments.""" if not isinstance(tags, list): raise Exception, "Package tags must be a list: %s" % tags if not isinstance(extras, dict): raise Exception, "Package extras must be a dict: %s" % tags package = {} package['name'] = self.coerce_package_name(name) package['title'] = title package['url'] = url package['notes'] = notes package['maintainer'] = maintainer package['maintainer_email'] = maintainer_email package['author'] = author package['author_email'] = author_email package['tags'] = tags package['extras'] = extras # Pre and post licenses servicization. if license_id != None: package['license_id'] = license_id elif license != None: package['license'] = license package['resources'] = resources return package def coerce_package_name(self, name): """Converts unicode string to valid CKAN package name.""" # Todo: Probably needs to be finished off. name = self.substitute_ascii_equivalents(name) name = name.lower() return name def substitute_ascii_equivalents(self, unicrap): # Method taken from: http://code.activestate.com/recipes/251871/ """This takes a UNICODE string and replaces Latin-1 characters with something equivalent in 7-bit ASCII. It returns a plain ASCII string. This function makes a best effort to convert Latin-1 characters into ASCII equivalents. It does not just strip out the Latin-1 characters. All characters in the standard 7-bit ASCII range are preserved. In the 8th bit range all the Latin-1 accented letters are converted to unaccented equivalents. Most symbol characters are converted to something meaningful. Anything not converted is deleted. """ xlate = { 0xc0: 'A', 0xc1: 'A', 0xc2: 'A', 0xc3: 'A', 0xc4: 'A', 0xc5: 'A', 0xc6: 'Ae', 0xc7: 'C', 0xc8: 'E', 0xc9: 'E', 0xca: 'E', 0xcb: 'E', 0xcc: 'I', 0xcd: 'I', 0xce: 'I', 0xcf: 'I', 0xd0: 'Th', 0xd1: 'N', 0xd2: 'O', 0xd3: 'O', 0xd4: 'O', 0xd5: 'O', 0xd6: 'O', 0xd8: 'O', 0xd9: 'U', 0xda: 'U', 0xdb: 'U', 0xdc: 'U', 0xdd: 'Y', 0xde: 'th', 0xdf: 'ss', 0xe0: 'a', 0xe1: 'a', 0xe2: 'a', 0xe3: 'a', 0xe4: 'a', 0xe5: 'a', 0xe6: 'ae', 0xe7: 'c', 0xe8: 'e', 0xe9: 'e', 0xea: 'e', 0xeb: 'e', 0xec: 'i', 0xed: 'i', 0xee: 'i', 0xef: 'i', 0xf0: 'th', 0xf1: 'n', 0xf2: 'o', 0xf3: 'o', 0xf4: 'o', 0xf5: 'o', 0xf6: 'o', 0xf8: 'o', 0xf9: 'u', 0xfa: 'u', 0xfb: 'u', 0xfc: 'u', 0xfd: 'y', 0xfe: 'th', 0xff: 'y', #0xa1:'!', 0xa2:'{cent}', 0xa3:'{pound}', 0xa4:'{currency}', #0xa5:'{yen}', 0xa6:'|', 0xa7:'{section}', 0xa8:'{umlaut}', #0xa9:'{C}', 0xaa:'{^a}', 0xab:'<<', 0xac:'{not}', #0xad:'-', 0xae:'{R}', 0xaf:'_', 0xb0:'{degrees}', #0xb1:'{+/-}', 0xb2:'{^2}', 0xb3:'{^3}', 0xb4:"'", #0xb5:'{micro}', 0xb6:'{paragraph}', 0xb7:'*', 0xb8:'{cedilla}', #0xb9:'{^1}', 0xba:'{^o}', 0xbb:'>>', #0xbc:'{1/4}', 0xbd:'{1/2}', 0xbe:'{3/4}', 0xbf:'?', #0xd7:'*', 0xf7:'/' } r = '' for i in unicrap: if xlate.has_key(ord(i)): r += xlate[ord(i)] elif ord(i) >= 0x80: pass else: r += str(i) return r def create_package_resource(self, url='', format='', hash='', description=''): return { 'url': url, 'format': format, 'hash': hash, 'description': description, }
class TestCkanClient(CkanServerCase): @classmethod def setup_class(self): self.pid = self._start_ckan_server() self.test_base_location = "http://127.0.0.1:5000/api" self._wait_for_url(url=self.test_base_location) self._recreate_ckan_server_testdata(config_path) # this is api key created for tester user by create-test-data in ckan test_api_key = "tester" test_api_key2 = "tester2" self.c = CkanClient(base_location=self.test_base_location, api_key=test_api_key, is_verbose=True) self.c2 = CkanClient(base_location=self.test_base_location, api_key=test_api_key2, is_verbose=True) @classmethod def teardown_class(self): self._stop_ckan_server(self.pid) def delete_relationships(self): res = self.c.package_relationship_register_get("annakarenina") if self.c.last_status == 200: if self.c.last_message: for rel_dict in self.c.last_message: self.c.package_relationship_entity_delete(rel_dict["subject"], rel_dict["type"], rel_dict["object"]) def test_01_get_locations(self): rest_base = self.test_base_location + "/rest" search_base = self.test_base_location + "/search" url = self.c.get_location("Base") assert url == self.test_base_location, url url = self.c.get_location("Package Register") assert url == rest_base + "/package" url = self.c.get_location("Package Entity", "myname") assert url == rest_base + "/package/myname" url = self.c.get_location("Package Entity", "myname", "relationships") assert url == rest_base + "/package/myname/relationships" url = self.c.get_location("Package Entity", "myname", "relationships", "name2") assert url == rest_base + "/package/myname/relationships/name2" url = self.c.get_location("Package Entity", "myname", "child_of", "name2") assert url == rest_base + "/package/myname/child_of/name2" url = self.c.get_location("Group Register") assert url == rest_base + "/group" url = self.c.get_location("Group Entity", "myname") assert url == rest_base + "/group/myname" url = self.c.get_location("Tag Register") assert url == rest_base + "/tag" url = self.c.get_location("Tag Entity", "myname") assert url == rest_base + "/tag/myname" url = self.c.get_location("Tag Entity", "myname") assert url == rest_base + "/tag/myname" url = self.c.get_location("Package Search") assert url == search_base + "/package" def test_02_get_api_version(self): version = self.c.api_version_get() status = self.c.last_status assert status == 200 body = self.c.last_body assert "version" in body, body assert int(version) > 0, version def test_03_package_register_get(self): self.c.package_register_get() status = self.c.last_status assert status == 200 body = self.c.last_body assert "annakarenina" in body, body assert type(self.c.last_message) == list assert "annakarenina" in self.c.last_message def test_04_package_entity_get(self): # Check registered entity is found. self.c.package_entity_get("annakarenina") status = self.c.last_status assert status == 200, status body = self.c.last_body assert "annakarenina" in body assert self.c.last_message message = self.c.last_message assert type(message) == dict assert message["name"] == u"annakarenina" assert message["title"] == u"A Novel By Tolstoy" def test_05_package_entity_get_404(self): # Check unregistered entity is not found. assert_raises(CkanApiError, self.c.package_entity_get, "mycoffeecup") status = self.c.last_status assert status == 404, status @classmethod def _generate_pkg_name(self): pkg_name = "ckanclienttest" import time timestr = str(time.time()).replace(".", "") pkg_name += timestr return pkg_name def test_06_package_register_post(self): pkg_name = self._generate_pkg_name() # Check package isn't registered. assert_raises(CkanApiError, self.c.package_entity_get, pkg_name) status = self.c.last_status assert status == 404, status # Check registration of new package. package = { "name": pkg_name, "url": "orig_url", "download_url": "orig_download_url", "tags": ["russian", "newtag"], "extras": {"genre": "thriller", "format": "ebook"}, } self.c.package_register_post(package) status = self.c.last_status assert status == 201, status # Check package is registered. self.c.package_entity_get(pkg_name) status = self.c.last_status assert status == 200, status message = self.c.last_message assert message assert "name" in message, repr(message) name = message["name"] assert name == pkg_name url = message["url"] assert url == "orig_url" download_url = message["download_url"] assert download_url == "orig_download_url" tags = message["tags"] # order out is not guaranteed assert set(tags) == set(["newtag", "russian"]), tags extras = message["extras"] assert extras == package["extras"] def test_07_package_entity_put(self): # Register new package. pkg_name_test_07 = self._generate_pkg_name() package = { "name": pkg_name_test_07, "url": "orig_url", "download_url": "orig_download_url", "tags": ["russian"], } self.c.package_register_post(package) status = self.c.last_status assert status == 201, status # Check update of existing package. mytag = "mytag" + pkg_name_test_07 package = { "name": pkg_name_test_07, "url": "new_url", "download_url": "new_download_url", "tags": ["russian", "tolstoy", mytag], "extras": {"genre": "thriller", "format": "ebook"}, } self.c.package_entity_put(package) status = self.c.last_status assert status == 200 # Check package is updated. self.c.package_entity_get(pkg_name_test_07) status = self.c.last_status assert status == 200, status message = self.c.last_message name = message["name"] assert name == pkg_name_test_07 url = message["url"] assert url == "new_url" download_url = message["download_url"] assert download_url == "new_download_url" tags = message["tags"] # order out is not guaranteed assert set(tags) == set(["russian", "tolstoy", mytag]), tags extras = message["extras"] assert extras == package["extras"] def test_08_package_entity_delete(self): # create a package to be deleted pkg_name = self._generate_pkg_name() self.c.package_register_post({"name": pkg_name}) status = self.c.last_status assert status == 201, status # check it is readable self.c.package_entity_get(pkg_name) assert self.c.last_status == 200, self.c.last_status # delete it self.c.package_entity_delete(pkg_name) # see it is not readable by another user assert_raises(CkanApiError, self.c2.package_entity_get, pkg_name) assert self.c2.last_status == 403, self.c.last_status # see it is still readable by the author (therefore pkg admin) self.c.package_entity_get(pkg_name) assert self.c.last_status == 200, self.c.last_status def test_09_tag_register_get(self): self.c.tag_register_get() status = self.c.last_status assert status == 200 body = self.c.last_body assert "russian" in body assert type(self.c.last_message) == list assert "russian" in self.c.last_message def test_10_pkg_search_basic(self): res = self.c.package_search("Novel") status = self.c.last_status assert status == 200, status assert_equal(list(res["results"]), [u"annakarenina"]) assert_equal(res["count"], 1) def test_10_pkg_search_paged(self): res = self.c.package_search("russian", search_options={"limit": 1}) status = self.c.last_status assert status == 200, status all_results = list(res["results"]) assert set(all_results) >= set([u"annakarenina", u"warandpeace"]), all_results assert res["count"] >= 2, "%r %r" % (res, all_results) def test_10_pkg_search_options(self): res = self.c.package_search(None, search_options={"groups": "roger"}) status = self.c.last_status assert status == 200, status assert_equal(list(res["results"]), [u"annakarenina"]) assert_equal(res["count"], 1) def test_10_pkg_search_options_all_fields(self): res = self.c.package_search(None, search_options={"groups": "roger", "all_fields": True}) status = self.c.last_status assert status == 200, status assert_equal(res["count"], 1) assert_equal(list(res["results"])[0]["name"], u"annakarenina") def test_11_package_relationship_post(self): res = self.c.package_relationship_register_get("annakarenina") assert self.c.last_status == 200, self.c.last_status assert not self.c.last_message, self.c.last_body # create relationship res = self.c.package_relationship_entity_post("annakarenina", "child_of", "warandpeace", "some comment") try: assert self.c.last_status == 201, self.c.last_status finally: self.delete_relationships() def test_12_package_relationship_get(self): # create relationship res = self.c.package_relationship_entity_post("annakarenina", "child_of", "warandpeace", "some comment") # read relationship try: res = self.c.package_relationship_register_get("annakarenina") assert self.c.last_status == 200, self.c.last_status rels = self.c.last_message assert len(rels) == 1, rels assert rels[0]["subject"] == "annakarenina", rels[0] assert rels[0]["object"] == "warandpeace", rels[0] assert rels[0]["type"] == "child_of", rels[0] assert rels[0]["comment"] == "some comment", rels[0] finally: self.delete_relationships() def test_13_package_relationship_put(self): # create relationship res = self.c.package_relationship_entity_post("annakarenina", "child_of", "warandpeace", "some comment") # update relationship try: res = self.c.package_relationship_entity_put("annakarenina", "child_of", "warandpeace", "new comment") assert self.c.last_status == 200, self.c.last_status # read relationship res = self.c.package_relationship_register_get("annakarenina") assert self.c.last_status == 200, self.c.last_status rels = self.c.last_message assert len(rels) == 1, rels assert rels[0]["comment"] == "new comment", rels[0] finally: self.delete_relationships() def test_14_package_relationship_delete(self): # create relationship res = self.c.package_relationship_entity_post("annakarenina", "child_of", "warandpeace", "some comment") try: self.c.package_relationship_entity_delete("annakarenina", "child_of", "warandpeace") # read relationship gives 404 assert_raises( CkanApiError, self.c.package_relationship_register_get, "annakarenina", "child_of", "warandpeace" ) assert self.c.last_status == 404, self.c.last_status # and register of relationships is blank res = self.c.package_relationship_register_get("annakarenina", "relationships", "warandpeace") assert self.c.last_status == 200, self.c.last_status assert not res, res finally: self.delete_relationships() def test_15_package_edit_form_get(self): try: import ckanext.dgu except exceptions.ImportError, e: raise SkipTest("Need dgu_form_api plugin (from ckanext-dgu) installed to test form api client.") if "dgu_form_api" not in config.get("ckan.plugins", ""): raise SkipTest("Need dgu_form_api plugin (from ckanext-dgu) enabled to test form api client.") res = self.c.package_edit_form_get("annakarenina") assert self.c.last_status == 200, self.c.last_status assert res, res