Exemple #1
0
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)
Exemple #2
0
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)
Exemple #3
0
 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()
Exemple #4
0
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
Exemple #6
0
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,
        }
Exemple #7
0
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)
Exemple #8
0
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