[ckan-changes] commit/ckan: 6 new changesets
Bitbucket
commits-noreply at bitbucket.org
Thu Jul 28 15:20:56 UTC 2011
6 new changesets in ckan:
http://bitbucket.org/okfn/ckan/changeset/cf9764903ce8/
changeset: cf9764903ce8
user: dread
date: 2011-07-26 19:04:55
summary: [doc][s]: Account for WebOb problems.
affected #: 1 file (614 bytes)
--- a/README.txt Tue Jul 26 17:55:11 2011 +0100
+++ b/README.txt Tue Jul 26 18:04:55 2011 +0100
@@ -102,35 +102,28 @@
pip install --ignore-installed -e hg+http://bitbucket.org/okfn/ckan#egg=ckan
- CKAN has a set of dependencies it requires which you should install too:
+ CKAN has dependent packages it requires you install. They are listed in the three pyenv/src/ckan/requires files.
- ::
-
- pip install --ignore-installed -r pyenv/src/ckan/requires/lucid_missing.txt -r pyenv/src/ckan/requires/lucid_conflict.txt
-
- The ``--ignore-installed`` option ensures ``pip`` installs software into
- this virtual environment even if it is already present on the system.
-
- If you are using Ubuntu Lucid you can install the rest of the dependencies
- from the system versions like this:
-
- ::
+ If you are running Ubuntu Lucid then it is recommended you take advantage of the Lucid packages to cover the dependencies listed in lucid_present.txt. In this case you should install the Lucid present packages::
sudo apt-get install python-psycopg2 python-lxml python-sphinx
sudo apt-get install python-pylons python-formalchemy python-repoze.who
sudo apt-get install python-repoze.who-plugins python-tempita python-zope.interface
- If you are not using Ubuntu Lucid you'll still need to install all the
- dependencies that would have been met in the ``apt-get install`` command
- at the start. You can do so like this:
+ And the remaining (non-Lucid) packages are installed like this::
- ::
+ pip install --ignore-installed -r pyenv/src/ckan/requires/lucid_missing.txt -r pyenv/src/ckan/requires/lucid_conflict.txt
- pip install --ignore-installed -r pyenv/src/ckan/requires/lucid_present.txt
+ If you are not using Ubuntu Lucid then should install all three sets of dependencies with this single command::
+
+ pip install --ignore-installed -r pyenv/src/ckan/requires/lucid_present.txt -r pyenv/src/ckan/requires/lucid_missing.txt -r pyenv/src/ckan/requires/lucid_conflict.txt
This will take a **long** time. Particularly the install of the ``lxml``
package.
+ The ``--ignore-installed`` option ensures ``pip`` installs software into
+ this virtual environment even if it is already present on the system. Because of this, to ensure you get a mutually agreeable version of WebOb installed, you shouldn't install each requirements file on its own with this option.
+
At this point you will need to deactivate and then re-activate your
virtual environment to ensure that all the scripts point to the correct
locations:
@@ -204,6 +197,10 @@
Other configuration, such as setting the language of the site or editing the
visual theme are described in :doc:`configuration` (doc/configuration.rst)
+ .. note ::
+
+ If the paster command gives you ``ImportError: cannot import name UnicodeMultiDict`` then you have gotten a version of WebOb that is too new for our Pylons. This usually occurs if you install Remove WebOb and reinstall version 1.0.8.
+
.. caution ::
Advanced users: If you are using CKAN's fab file capability you currently need to create
http://bitbucket.org/okfn/ckan/changeset/5bce6b3ef1ed/
changeset: 5bce6b3ef1ed
branch: enh-1236-view-package-revision
user: dread
date: 2011-07-27 12:11:43
summary: [tests]: Add failing test to show problem with showing old revision details.
affected #: 2 files (1.8 KB)
--- a/ckan/templates/package/read.html Tue Jul 26 17:54:50 2011 +0100
+++ b/ckan/templates/package/read.html Wed Jul 27 11:11:43 2011 +0100
@@ -97,7 +97,7 @@
<div id="revision" class="widget-container"><p py:if="c.pkg_revision_not_latest">This is an old revision of this package, as edited <!--!by ${h.linked_user(rev.author)}-->at ${h.render_datetime(c.pkg_revision_timestamp)}. It may differ significantly from the <a href="${url(controller='package', action='read', id=c.pkg.name)}">current revision</a>.</p><p py:if="not c.pkg_revision_not_latest">This is the current revision of this package, as edited <!--!by ${h.linked_user(rev.author)}-->at ${h.render_datetime(c.pkg_revision_timestamp)}.</p>
- </div>
+ </div><!-- #revision --></py:if><xi:include href="read_core.html" />
--- a/ckan/tests/functional/test_package.py Tue Jul 26 17:54:50 2011 +0100
+++ b/ckan/tests/functional/test_package.py Wed Jul 27 11:11:43 2011 +0100
@@ -437,6 +437,7 @@
cls.date1 = datetime.datetime(2011, 1, 1)
cls.date2 = datetime.datetime(2011, 1, 2)
cls.date3 = datetime.datetime(2011, 1, 3)
+ cls.date4 = datetime.datetime(2011, 1, 4)
cls.today = datetime.datetime.now()
cls.pkg_name = u'testpkg'
@@ -448,7 +449,7 @@
model.setup_default_user_roles(pkg)
model.repo.commit_and_remove()
- # edit package
+ # edit package 2
rev = model.repo.new_revision()
rev.timestamp = cls.date2
pkg = model.Package.by_name(cls.pkg_name)
@@ -457,7 +458,7 @@
pkg.extras = {'key2': u'value2'}
model.repo.commit_and_remove()
- # edit package again
+ # edit package 3
rev = model.repo.new_revision()
rev.timestamp = cls.date3
pkg = model.Package.by_name(cls.pkg_name)
@@ -466,6 +467,13 @@
pkg.extras['key2'] = u'value3'
model.repo.commit_and_remove()
+ # edit package 4
+ rev = model.repo.new_revision()
+ rev.timestamp = cls.date4
+ pkg = model.Package.by_name(cls.pkg_name)
+ pkg.add_tag_by_name(u'tag4')
+ model.repo.commit_and_remove()
+
cls.offset = url_for(controller='package',
action='read',
id=cls.pkg_name)
@@ -479,6 +487,8 @@
def test_read_normally(self):
res = self.app.get(self.offset, status=200)
+ main_html = self.main_div(res)
+ assert 'as edited at' not in main_html
pkg_html = self.named_div('package', res)
side_html = self.named_div('primary', res)
print 'PKG', pkg_html
@@ -486,12 +496,17 @@
assert 'key2' in pkg_html
assert 'value3' in pkg_html
print 'SIDE', side_html
+ assert 'tag4' in side_html
assert 'tag3' in side_html
assert 'tag2' in side_html
def test_read_date1(self):
offset = self.offset + self.date1.strftime('@%Y-%m-%d')
res = self.app.get(offset, status=200)
+ rev_html = self.named_div('revision', res)
+ print 'REV', rev_html
+ expected_date = self.date1.strftime('as edited at %Y-%m-%d %H:%M.')
+ assert expected_date in rev_html, expected_date
pkg_html = self.named_div('package', res)
side_html = self.named_div('primary', res)
print 'PKG', pkg_html
@@ -506,6 +521,10 @@
date2_plus_3h = self.date2 + datetime.timedelta(hours=3)
offset = self.offset + date2_plus_3h.strftime('@%Y-%m-%d')
res = self.app.get(offset, status=200)
+ rev_html = self.named_div('revision', res)
+ print 'REV', rev_html
+ expected_date = self.date2.strftime('as edited at %Y-%m-%d %H:%M.')
+ assert expected_date in rev_html, expected_date
pkg_html = self.named_div('package', res)
side_html = self.named_div('primary', res)
print 'PKG', pkg_html
@@ -519,6 +538,10 @@
def test_read_date3(self):
offset = self.offset + self.date3.strftime('@%Y-%m-%d-%H-%M')
res = self.app.get(offset, status=200)
+ rev_html = self.named_div('revision', res)
+ print 'REV', rev_html
+ expected_date = self.date3.strftime('as edited at %Y-%m-%d %H:%M.')
+ assert expected_date in rev_html, expected_date
pkg_html = self.named_div('package', res)
side_html = self.named_div('primary', res)
print 'PKG', pkg_html
@@ -526,6 +549,25 @@
assert 'key2' in pkg_html
assert 'value3' in pkg_html
print 'SIDE', side_html
+ assert 'tag4' not in side_html
+ assert 'tag3' in side_html
+ assert 'tag2' in side_html
+
+ def test_read_date4(self):
+ offset = self.offset + self.date4.strftime('@%Y-%m-%d-%H-%M')
+ res = self.app.get(offset, status=200)
+ rev_html = self.named_div('revision', res)
+ print 'REV', rev_html
+ expected_date = self.date4.strftime('as edited at %Y-%m-%d %H:%M.')
+ assert expected_date in rev_html, expected_date
+ pkg_html = self.named_div('package', res)
+ side_html = self.named_div('primary', res)
+ print 'PKG', pkg_html
+ assert 'title3' in pkg_html
+ assert 'key2' in pkg_html
+ assert 'value3' in pkg_html
+ print 'SIDE', side_html
+ assert 'tag4' in side_html
assert 'tag3' in side_html
assert 'tag2' in side_html
http://bitbucket.org/okfn/ckan/changeset/d3084ee3658f/
changeset: d3084ee3658f
branch: enh-1236-view-package-revision
user: dread
date: 2011-07-27 14:53:14
summary: [merge] from default.
affected #: 15 files (9.3 KB)
--- a/ckan/config/routing.py Wed Jul 27 11:11:43 2011 +0100
+++ b/ckan/config/routing.py Wed Jul 27 13:53:14 2011 +0100
@@ -104,6 +104,8 @@
map.connect('/api/rest', controller='api', action='index')
+ map.connect('/api/action/{logic_function}', controller='api', action='action')
+
map.connect('/api/rest/{register}', controller='api', action='list',
requirements=dict(register=register_list_str),
conditions=dict(method=['GET'])
--- a/ckan/controllers/api.py Wed Jul 27 11:11:43 2011 +0100
+++ b/ckan/controllers/api.py Wed Jul 27 13:53:14 2011 +0100
@@ -11,6 +11,7 @@
from ckan.plugins import PluginImplementations, IGroupController
from ckan.lib.munge import munge_title_to_name
from ckan.lib.navl.dictization_functions import DataError
+from ckan.logic import get_action
import ckan.logic.action.get as get
import ckan.logic.action.create as create
import ckan.logic.action.update as update
@@ -30,6 +31,8 @@
}
class ApiController(BaseController):
+ _actions = {}
+
def __call__(self, environ, start_response):
self._identify_user()
if not self.authorizer.am_authorized(c, model.Action.SITE_READ, model.System):
@@ -127,10 +130,45 @@
response_data = {}
response_data['version'] = ver or '1'
return self._finish_ok(response_data)
+
+ def action(self, logic_function):
+ function = get_action(logic_function)
+
+ context = {'model': model, 'session': model.Session, 'user': c.user}
+ model.Session()._context = context
+ return_dict = {'help': function.__doc__}
+
+ try:
+ request_data = self._get_request_data()
+ except ValueError, inst:
+
+ return self._finish_bad_request(
+ gettext('JSON Error: %s') % str(inst))
+ try:
+ result = function(context, request_data)
+ return_dict['success'] = True
+ return_dict['result'] = result
+ except DataError:
+ log.error('Format incorrect: %s' % request_data)
+ #TODO make better error message
+ return self._finish(400, _(u'Integrity Error') % request_data)
+ except NotAuthorized:
+ return_dict['error'] = {'__type': 'Authorization Error',
+ 'message': _('Access denied')}
+ return_dict['success'] = False
+ return self._finish(403, return_dict, content_type='json')
+ except ValidationError, e:
+ error_dict = e.error_dict
+ error_dict['__type'] = 'Validtion Error'
+ return_dict['error'] = error_dict
+ return_dict['success'] = False
+ log.error('Validation error: %r' % str(e.error_dict))
+ return self._finish(409, return_dict, content_type='json')
+ return self._finish_ok(return_dict)
def list(self, ver=None, register=None, subregister=None, id=None):
context = {'model': model, 'session': model.Session,
- 'user': c.user, 'id': id, 'api_version': ver}
+ 'user': c.user, 'api_version': ver}
log.debug('listing: %s' % context)
action_map = {
'revision': get.revision_list,
@@ -149,7 +187,7 @@
return self._finish_bad_request(
gettext('Cannot list entity of this type: %s') % register)
try:
- return self._finish_ok(action(context))
+ return self._finish_ok(action(context, {'id': id}))
except NotFound, e:
extra_msg = e.extra_msg
return self._finish_not_found(extra_msg)
@@ -166,8 +204,9 @@
}
context = {'model': model, 'session': model.Session, 'user': c.user,
- 'id': id, 'id2': id2, 'rel': subregister,
'api_version': ver}
+ data_dict = {'id': id, 'id2': id2, 'rel': subregister}
+
for type in model.PackageRelationship.get_all_types():
action_map[('package', type)] = get.package_relationships_list
log.debug('show: %s' % context)
@@ -180,7 +219,7 @@
gettext('Cannot read entity of this type: %s') % register)
try:
- return self._finish_ok(action(context))
+ return self._finish_ok(action(context, data_dict))
except NotFound, e:
extra_msg = e.extra_msg
return self._finish_not_found(extra_msg)
@@ -193,22 +232,22 @@
def create(self, ver=None, register=None, subregister=None, id=None, id2=None):
action_map = {
- ('package', 'relationships'): create.package_relationship_create,
- 'group': create.group_create_rest,
- 'package': create.package_create_rest,
- 'rating': create.rating_create,
+ ('package', 'relationships'): get_action('package_relationship_create'),
+ 'group': get_action('group_create_rest'),
+ 'package': get_action('package_create_rest'),
+ 'rating': get_action('rating_create'),
}
for type in model.PackageRelationship.get_all_types():
action_map[('package', type)] = create.package_relationship_create
-
context = {'model': model, 'session': model.Session, 'user': c.user,
- 'id': id, 'id2': id2, 'rel': subregister,
'api_version': ver}
log.debug('create: %s' % (context))
try:
request_data = self._get_request_data()
+ data_dict = {'id': id, 'id2': id2, 'rel': subregister}
+ data_dict.update(request_data)
except ValueError, inst:
return self._finish_bad_request(
gettext('JSON Error: %s') % str(inst))
@@ -221,10 +260,10 @@
gettext('Cannot create new entity of this type: %s %s') % \
(register, subregister))
try:
- response_data = action(request_data, context)
+ response_data = action(context, data_dict)
location = None
- if "id" in context:
- location = str('%s/%s' % (request.path, context.get("id")))
+ if "id" in data_dict:
+ location = str('%s/%s' % (request.path, data_dict.get("id")))
return self._finish_ok(response_data,
resource_location=location)
except NotAuthorized:
@@ -243,19 +282,20 @@
def update(self, ver=None, register=None, subregister=None, id=None, id2=None):
action_map = {
- ('package', 'relationships'): update.package_relationship_update,
- 'package': update.package_update_rest,
- 'group': update.group_update_rest,
+ ('package', 'relationships'): get_action('package_relationship_update'),
+ 'package': get_action('package_update_rest'),
+ 'group': get_action('group_update_rest'),
}
for type in model.PackageRelationship.get_all_types():
action_map[('package', type)] = update.package_relationship_update
context = {'model': model, 'session': model.Session, 'user': c.user,
- 'id': id, 'id2': id2, 'rel': subregister,
- 'api_version': ver}
+ 'api_version': ver, 'id': id}
log.debug('update: %s' % (context))
try:
request_data = self._get_request_data()
+ data_dict = {'id': id, 'id2': id2, 'rel': subregister}
+ data_dict.update(request_data)
except ValueError, inst:
return self._finish_bad_request(
gettext('JSON Error: %s') % str(inst))
@@ -267,7 +307,7 @@
gettext('Cannot update entity of this type: %s') % \
register.encode('utf-8'))
try:
- response_data = action(request_data, context)
+ response_data = action(context, data_dict)
return self._finish_ok(response_data)
except NotAuthorized:
return self._finish_not_authz()
@@ -510,3 +550,4 @@
resultSet["ResultSet"]["Result"].append(result)
return self._finish_ok(resultSet)
+
--- a/ckan/controllers/group.py Wed Jul 27 11:11:43 2011 +0100
+++ b/ckan/controllers/group.py Wed Jul 27 13:53:14 2011 +0100
@@ -115,13 +115,14 @@
'user': c.user or c.author, 'extras_as_string': True,
'save': 'save' in request.params,
'schema': self._form_to_db_schema(),
- 'id': id}
+ }
+ data_dict = {'id': id}
if context['save'] and not data:
return self._save_edit(id, context)
try:
- old_data = get.group_show(context)
+ old_data = get.group_show(context, data_dict)
c.grouptitle = old_data.get('title')
c.groupname = old_data.get('name')
schema = self._db_to_form_schema()
@@ -151,7 +152,7 @@
data_dict = clean_dict(unflatten(
tuplize_dict(parse_params(request.params))))
context['message'] = data_dict.get('log_message', '')
- group = create.group_create(data_dict, context)
+ group = create.group_create(context, data_dict)
h.redirect_to(controller='group', action='read', id=group['name'])
except NotAuthorized:
abort(401, _('Unauthorized to read group %s') % '')
@@ -169,7 +170,8 @@
data_dict = clean_dict(unflatten(
tuplize_dict(parse_params(request.params))))
context['message'] = data_dict.get('log_message', '')
- group = update.group_update(data_dict, context)
+ data_dict['id'] = id
+ group = update.group_update(context, data_dict)
h.redirect_to(controller='group', action='read', id=group['name'])
except NotAuthorized:
abort(401, _('Unauthorized to read group %s') % id)
--- a/ckan/controllers/home.py Wed Jul 27 11:11:43 2011 +0100
+++ b/ckan/controllers/home.py Wed Jul 27 13:53:14 2011 +0100
@@ -50,7 +50,8 @@
c.package_count = query.count
c.latest_packages = current_package_list_with_resources({'model': model,
'user': c.user,
- 'limit': 5})
+ 'limit': 5},
+ {})
return render('home/index.html', cache_key=cache_key,
cache_expire=cache_expires)
--- a/ckan/controllers/package.py Wed Jul 27 11:11:43 2011 +0100
+++ b/ckan/controllers/package.py Wed Jul 27 13:53:14 2011 +0100
@@ -16,6 +16,7 @@
import ckan.logic.action.create as create
import ckan.logic.action.update as update
import ckan.logic.action.get as get
+from ckan.logic import get_action
from ckan.logic.schema import package_form_schema
from ckan.lib.base import request, c, BaseController, model, abort, h, g, render
from ckan.lib.base import etag_cache, response, redirect, gettext
@@ -77,9 +78,9 @@
log.info('incorrect form fields posted')
raise DataError(data_dict)
- def _setup_template_variables(self, context):
- c.groups = get.group_list_availible(context)
- c.groups_authz = get.group_list_authz(context)
+ def _setup_template_variables(self, context, data_dict):
+ c.groups = get.group_list_availible(context, data_dict)
+ c.groups_authz = get.group_list_authz(context, data_dict)
c.licences = [('', '')] + model.Package.get_license_options()
c.is_sysadmin = Authorizer().is_sysadmin(c.user)
c.resource_columns = model.Resource.get_columns()
@@ -174,13 +175,13 @@
def read(self, id):
context = {'model': model, 'session': model.Session,
'user': c.user or c.author, 'extras_as_string': True,
- 'schema': self._form_to_db_schema(),
- 'id': id}
+ 'schema': self._form_to_db_schema()}
+ data_dict = {'id': id}
# interpret @<revision_id> or @<date> suffix
split = id.split('@')
if len(split) == 2:
- context['id'], revision_ref = split
+ data_dict['id'], revision_ref = split
if model.is_id(revision_ref):
context['revision_id'] = revision_ref
else:
@@ -196,7 +197,7 @@
#check if package exists
try:
- c.pkg_dict = get.package_show(context)
+ c.pkg_dict = get.package_show(context, data_dict)
c.pkg = context['package']
except NotFound:
abort(404, _('Package not found'))
@@ -227,12 +228,11 @@
def comments(self, id):
context = {'model': model, 'session': model.Session,
'user': c.user or c.author, 'extras_as_string': True,
- 'schema': self._form_to_db_schema(),
- 'id': id}
+ 'schema': self._form_to_db_schema()}
#check if package exists
try:
- c.pkg_dict = get.package_show(context)
+ c.pkg_dict = get.package_show(context, {'id':id})
c.pkg = context['package']
except NotFound:
abort(404, _('Package not found'))
@@ -329,7 +329,7 @@
error_summary = error_summary or {}
vars = {'data': data, 'errors': errors, 'error_summary': error_summary}
- self._setup_template_variables(context)
+ self._setup_template_variables(context, {'id': id})
c.form = render(self.package_form, extra_vars=vars)
return render('package/new.html')
@@ -339,14 +339,14 @@
'user': c.user or c.author, 'extras_as_string': True,
'preview': 'preview' in request.params,
'save': 'save' in request.params,
- 'id': id, 'moderated': config.get('moderated'),
+ 'moderated': config.get('moderated'),
'pending': True,
'schema': self._form_to_db_schema()}
if (context['save'] or context['preview']) and not data:
return self._save_edit(id, context)
try:
- old_data = get.package_show(context)
+ old_data = get.package_show(context, {'id':id})
schema = self._db_to_form_schema()
if schema:
old_data, errors = validate(old_data, schema)
@@ -365,19 +365,19 @@
errors = errors or {}
vars = {'data': data, 'errors': errors, 'error_summary': error_summary}
- self._setup_template_variables(context)
+ self._setup_template_variables(context, {'id':'id'})
c.form = render(self.package_form, extra_vars=vars)
return render('package/edit.html')
def read_ajax(self, id, revision=None):
context = {'model': model, 'session': model.Session,
'user': c.user or c.author,
- 'id': id, 'extras_as_string': True,
+ 'extras_as_string': True,
'schema': self._form_to_db_schema(),
'revision_id': revision}
try:
- data = get.package_show(context)
+ data = get.package_show(context, {'id': id})
schema = self._db_to_form_schema()
if schema:
data, errors = validate(data, schema)
@@ -395,9 +395,6 @@
def history_ajax(self, id):
- context = {'model': model, 'session': model.Session,
- 'user': c.user or c.author,
- 'id': id, 'extras_as_string': True}
pkg = model.Package.get(id)
data = []
approved = False
@@ -424,7 +421,7 @@
tuplize_dict(parse_params(request.POST))))
self._check_data_dict(data_dict)
context['message'] = data_dict.get('log_message', '')
- pkg = create.package_create(data_dict, context)
+ pkg = get_action('package_create')(context, data_dict)
if context['preview']:
PackageSaver().render_package(pkg, context)
@@ -454,9 +451,10 @@
context['message'] = data_dict.get('log_message', '')
if not context['moderated']:
context['pending'] = False
- pkg = update.package_update(data_dict, context)
+ data_dict['id'] = id
+ pkg = get_action('package_update')(context, data_dict)
if request.params.get('save', '') == 'Approve':
- update.make_latest_pending_package_active(context)
+ update.make_latest_pending_package_active(context, data_dict)
c.pkg = context['package']
c.pkg_dict = pkg
--- a/ckan/lib/dictization/model_save.py Wed Jul 27 11:11:43 2011 +0100
+++ b/ckan/lib/dictization/model_save.py Wed Jul 27 13:53:14 2011 +0100
@@ -105,7 +105,7 @@
extra = old_extras[key]
if extra.state == 'deleted':
continue
- state = 'pending-deleted' if context.get('pending') else 'delete'
+ state = 'pending-deleted' if context.get('pending') else 'deleted'
extra.state = state
def group_extras_save(extras_dicts, context):
@@ -126,7 +126,6 @@
return result_dict
def package_tag_list_save(tag_dicts, package, context):
-
allow_partial_update = context.get("allow_partial_update", False)
if not tag_dicts and allow_partial_update:
--- a/ckan/logic/__init__.py Wed Jul 27 11:11:43 2011 +0100
+++ b/ckan/logic/__init__.py Wed Jul 27 13:53:14 2011 +0100
@@ -1,6 +1,8 @@
import logging
import ckan.authz
from ckan.lib.navl.dictization_functions import flatten_dict
+from ckan.plugins import PluginImplementations
+from ckan.plugins.interfaces import IActions
class ActionError(Exception):
def __init__(self, extra_msg=None):
@@ -90,4 +92,42 @@
log.debug("No valid API key provided.")
raise NotAuthorized
log.debug("Access OK.")
- return True
+ return True
+
+_actions = {}
+
+def get_action(action):
+ if _actions:
+ return _actions.get(action)
+ # Otherwise look in all the plugins to resolve all possible
+ # First get the default ones in the ckan/logic/action directory
+ # Rather than writing them out in full will use __import__
+ # to load anything from ckan.logic.action that looks like it might
+ # be an action
+ for action_module_name in ['get', 'create', 'update']:
+ module_path = 'ckan.logic.action.'+action_module_name
+ module = __import__(module_path)
+ for part in module_path.split('.')[1:]:
+ module = getattr(module, part)
+ for k, v in module.__dict__.items():
+ if not k.startswith('_'):
+ _actions[k] = v
+ # Then overwrite them with any specific ones in the plugins:
+ resolved_action_plugins = {}
+ fetched_actions = {}
+ for plugin in PluginImplementations(IActions):
+ for name, auth_function in plugin.get_actions().items():
+ if name in resolved_action_plugins:
+ raise Exception(
+ 'The action %r is already implemented in %r' % (
+ name,
+ resolved_action_plugins[name]
+ )
+ )
+ log.debug('Auth function %r was inserted', plugin.name)
+ resolved_action_plugins[name] = plugin.name
+ fetched_actions[name] = auth_function
+ # Use the updated ones in preference to the originals.
+ _actions.update(fetched_actions)
+ return _actions.get(action)
+
--- a/ckan/logic/action/create.py Wed Jul 27 11:11:43 2011 +0100
+++ b/ckan/logic/action/create.py Wed Jul 27 13:53:14 2011 +0100
@@ -30,16 +30,17 @@
check_group_auth)
log = logging.getLogger(__name__)
-def package_create(data_dict, context):
+def package_create(context, data_dict):
model = context['model']
user = context['user']
preview = context.get('preview', False)
schema = context.get('schema') or default_create_package_schema()
model.Session.remove()
+ model.Session()._context = context
check_access(model.System(), model.Action.PACKAGE_CREATE, context)
- check_group_auth(data_dict, context)
+ check_group_auth(context, data_dict)
data, errors = validate(data_dict, schema, context)
@@ -76,7 +77,26 @@
else:
return data
-def resource_create(data_dict, context):
+def package_create_validate(context, data_dict):
+ model = context['model']
+ user = context['user']
+ preview = context.get('preview', False)
+ schema = context.get('schema') or default_create_package_schema()
+ model.Session.remove()
+ model.Session()._context = context
+
+ check_access(model.System(), model.Action.PACKAGE_CREATE, context)
+ check_group_auth(context, data_dict)
+
+ data, errors = validate(data_dict, schema, context)
+
+ if errors:
+ model.Session.rollback()
+ raise ValidationError(errors, package_error_summary(errors))
+ else:
+ return data
+
+def resource_create(context, data_dict):
model = context['model']
user = context['user']
@@ -84,14 +104,13 @@
default_resource_schema(),
context)
-
-def package_relationship_create(data_dict, context):
+def package_relationship_create(context, data_dict):
model = context['model']
user = context['user']
- id = context["id"]
- id2 = context["id2"]
- rel_type = context["rel"]
+ id = data_dict["id"]
+ id2 = data_dict["id2"]
+ rel_type = data_dict["rel"]
api = context.get('api_version') or '1'
ref_package_by = 'id' if api == '2' else 'name'
@@ -124,7 +143,7 @@
relationship_dicts = rel.as_dict(ref_package_by=ref_package_by)
return relationship_dicts
-def group_create(data_dict, context):
+def group_create(context, data_dict):
model = context['model']
user = context['user']
schema = context.get('schema') or default_group_schema()
@@ -160,7 +179,7 @@
log.debug('Created object %s' % str(group.name))
return group_dictize(group, context)
-def rating_create(data_dict, context):
+def rating_create(context, data_dict):
model = context['model']
user = context.get("user")
@@ -197,12 +216,12 @@
## Modifications for rest api
-def package_create_rest(data_dict, context):
+def package_create_rest(context, data_dict):
api = context.get('api_version') or '1'
dictized_package = package_api_to_dict(data_dict, context)
- dictized_after = package_create(dictized_package, context)
+ dictized_after = package_create(context, dictized_package)
pkg = context['package']
@@ -211,14 +230,16 @@
else:
package_dict = package_to_api2(pkg, context)
+ data_dict['id'] = pkg.id
+
return package_dict
-def group_create_rest(data_dict, context):
+def group_create_rest(context, data_dict):
api = context.get('api_version') or '1'
dictized_group = group_api_to_dict(data_dict, context)
- dictized_after = group_create(dictized_group, context)
+ dictized_after = group_create(context, dictized_group)
group = context['group']
@@ -227,5 +248,7 @@
else:
group_dict = group_to_api2(group, context)
+ data_dict['id'] = group.id
+
return group_dict
--- a/ckan/logic/action/get.py Wed Jul 27 11:11:43 2011 +0100
+++ b/ckan/logic/action/get.py Wed Jul 27 13:53:14 2011 +0100
@@ -14,20 +14,21 @@
group_dictize)
-def package_list(context):
+def package_list(context, data_dict):
+ '''Lists the package by name'''
model = context["model"]
user = context["user"]
- api = context["api_version"]
+ api = context.get("api_version", '1')
ref_package_by = 'id' if api == '2' else 'name'
query = ckan.authz.Authorizer().authorized_query(user, model.Package)
packages = query.all()
return [getattr(p, ref_package_by) for p in packages]
-def current_package_list_with_resources(context):
+def current_package_list_with_resources(context, data_dict):
model = context["model"]
user = context["user"]
- limit = context.get("limit")
+ limit = data_dict.get("limit")
q = ckan.authz.Authorizer().authorized_query(user, model.PackageRevision)
q = q.filter(model.PackageRevision.state=='active')
@@ -56,15 +57,15 @@
package_list.append(result_dict)
return package_list
-def revision_list(context):
+def revision_list(context, data_dict):
model = context["model"]
revs = model.Session.query(model.Revision).all()
return [rev.id for rev in revs]
-def package_revision_list(context):
+def package_revision_list(context, data_dict):
model = context["model"]
- id = context["id"]
+ id = data_dict["id"]
pkg = model.Package.get(id)
if pkg is None:
raise NotFound
@@ -76,7 +77,7 @@
include_packages=False))
return revision_dicts
-def group_list(context):
+def group_list(context, data_dict):
model = context["model"]
user = context["user"]
api = context.get('api_version') or '1'
@@ -86,7 +87,7 @@
groups = query.all()
return [getattr(p, ref_group_by) for p in groups]
-def group_list_authz(context):
+def group_list_authz(context, data_dict):
model = context['model']
user = context['user']
pkg = context.get('package')
@@ -95,7 +96,7 @@
groups = set(query.all())
return dict((group.id, group.name) for group in groups)
-def group_list_availible(context):
+def group_list_availible(context, data_dict):
model = context['model']
user = context['user']
pkg = context.get('package')
@@ -108,30 +109,30 @@
return [(group.id, group.name) for group in groups]
-def licence_list(context):
+def licence_list(context, data_dict):
model = context["model"]
license_register = model.Package.get_license_register()
licenses = license_register.values()
licences = [l.as_dict() for l in licenses]
return licences
-def tag_list(context):
+def tag_list(context, data_dict):
model = context["model"]
tags = model.Session.query(model.Tag).all() #TODO
tag_list = [tag.name for tag in tags]
return tag_list
-def package_relationships_list(context):
+def package_relationships_list(context, data_dict):
##TODO needs to work with dictization layer
model = context['model']
user = context['user']
- id = context["id"]
- id2 = context.get("id2")
- rel = context.get("rel")
api = context.get('api_version') or '1'
+
+ id = data_dict["id"]
+ id2 = data_dict.get("id2")
+ rel = data_dict.get("rel")
ref_package_by = 'id' if api == '2' else 'name';
-
pkg1 = model.Package.get(id)
pkg2 = None
if not pkg1:
@@ -157,11 +158,11 @@
return relationship_dicts
-def package_show(context):
+def package_show(context, data_dict):
model = context['model']
api = context.get('api_version') or '1'
- id = context['id']
+ id = data_dict['id']
pkg = model.Package.get(id)
@@ -179,10 +180,10 @@
return package_dict
-def revision_show(context):
+def revision_show(context, data_dict):
model = context['model']
api = context.get('api_version') or '1'
- id = context['id']
+ id = data_dict['id']
ref_package_by = 'id' if api == '2' else 'name'
rev = model.Session.query(model.Revision).get(id)
@@ -192,9 +193,9 @@
ref_package_by=ref_package_by)
return rev_dict
-def group_show(context):
+def group_show(context, data_dict):
model = context['model']
- id = context['id']
+ id = data_dict['id']
api = context.get('api_version') or '1'
@@ -213,10 +214,10 @@
return group_dict
-def tag_show(context):
+def tag_show(context, data_dict):
model = context['model']
api = context.get('api_version') or '1'
- id = context['id']
+ id = data_dict['id']
ref_package_by = 'id' if api == '2' else 'name'
obj = model.Tag.get(id) #TODO tags
if obj is None:
@@ -226,12 +227,11 @@
return package_list
-def package_show_rest(context):
+def package_show_rest(context, data_dict):
- package_show(context)
+ package_show(context, data_dict)
api = context.get('api_version') or '1'
-
pkg = context['package']
if api == '1':
@@ -241,9 +241,9 @@
return package_dict
-def group_show_rest(context):
+def group_show_rest(context, data_dict):
- group_show(context)
+ group_show(context, data_dict)
api = context.get('api_version') or '1'
group = context['group']
--- a/ckan/logic/action/update.py Wed Jul 27 11:11:43 2011 +0100
+++ b/ckan/logic/action/update.py Wed Jul 27 13:53:14 2011 +0100
@@ -51,7 +51,7 @@
error_summary[_(prettify(key))] = error[0]
return error_summary
-def check_group_auth(data_dict, context):
+def check_group_auth(context, data_dict):
model = context['model']
pkg = context.get("package")
@@ -105,11 +105,11 @@
context['latest_revision_date'] = latest_rev.revision_timestamp
context['latest_revision'] = latest_rev.revision_id
-def make_latest_pending_package_active(context):
+def make_latest_pending_package_active(context, data_dict):
model = context['model']
session = model.Session
- id = context["id"]
+ id = data_dict["id"]
pkg = model.Package.get(id)
check_access(pkg, model.Action.EDIT, context)
@@ -146,26 +146,28 @@
session.remove()
-def package_update(data_dict, context):
+def package_update(context, data_dict):
model = context['model']
user = context['user']
- id = context["id"]
+
+ id = data_dict["id"]
preview = context.get('preview', False)
schema = context.get('schema') or default_update_package_schema()
model.Session.remove()
+ model.Session()._context = context
pkg = model.Package.get(id)
context["package"] = pkg
if pkg is None:
raise NotFound(_('Package was not found.'))
- context["id"] = pkg.id
+ data_dict["id"] = pkg.id
check_access(pkg, model.Action.EDIT, context)
data, errors = validate(data_dict, schema, context)
- check_group_auth(data, context)
+ check_group_auth(context, data)
if errors:
model.Session.rollback()
@@ -188,6 +190,31 @@
return package_dictize(pkg, context)
return data
+def package_update_validate(context, data_dict):
+ model = context['model']
+ user = context['user']
+
+ id = data_dict["id"]
+ preview = context.get('preview', False)
+ schema = context.get('schema') or default_update_package_schema()
+ model.Session.remove()
+ model.Session()._context = context
+
+ pkg = model.Package.get(id)
+ context["package"] = pkg
+
+ if pkg is None:
+ raise NotFound(_('Package was not found.'))
+ data_dict["id"] = pkg.id
+
+ check_access(pkg, model.Action.EDIT, context)
+ data, errors = validate(data_dict, schema, context)
+
+ if errors:
+ model.Session.rollback()
+ raise ValidationError(errors, package_error_summary(errors))
+ return data
+
def _update_package_relationship(relationship, comment, context):
model = context['model']
@@ -205,13 +232,13 @@
ref_package_by=ref_package_by)
return rel_dict
-def package_relationship_update(data_dict, context):
+def package_relationship_update(context, data_dict):
model = context['model']
user = context['user']
- id = context["id"]
- id2 = context["id2"]
- rel = context["rel"]
+ id = data_dict["id"]
+ id2 = data_dict["id2"]
+ rel = data_dict["rel"]
api = context.get('api_version') or '1'
ref_package_by = 'id' if api == '2' else 'name'
@@ -236,12 +263,12 @@
comment = data_dict.get('comment', u'')
return _update_package_relationship(entity, comment, context)
-def group_update(data_dict, context):
+def group_update(context, data_dict):
model = context['model']
user = context['user']
schema = context.get('schema') or default_update_group_schema()
- id = context['id']
+ id = data_dict['id']
group = model.Group.get(id)
context["group"] = group
@@ -276,16 +303,28 @@
## Modifications for rest api
-def package_update_rest(data_dict, context):
+def package_update_rest(context, data_dict):
model = context['model']
- id = context["id"]
+ id = data_dict.get("id")
+ request_id = context['id']
api = context.get('api_version') or '1'
- pkg = model.Package.get(id)
+ pkg = model.Package.get(request_id)
+
+ if not pkg:
+ raise NotFound
+
+ if id and id != pkg.id:
+ pkg_from_data = model.Package.get(id)
+ if pkg_from_data != pkg:
+ error_dict = {id:('Cannot change value of key from %s to %s. '
+ 'This key is read-only') % (pkg.id, id)}
+ raise ValidationError(error_dict)
+
context["package"] = pkg
context["allow_partial_update"] = True
dictized_package = package_api_to_dict(data_dict, context)
- dictized_after = package_update(dictized_package, context)
+ dictized_after = package_update(context, dictized_package)
pkg = context['package']
@@ -296,16 +335,16 @@
return package_dict
-def group_update_rest(data_dict, context):
+def group_update_rest(context, data_dict):
model = context['model']
- id = context["id"]
+ id = data_dict["id"]
api = context.get('api_version') or '1'
group = model.Group.get(id)
context["group"] = group
context["allow_partial_update"] = True
dictized_package = group_api_to_dict(data_dict, context)
- dictized_after = group_update(dictized_package, context)
+ dictized_after = group_update(context, dictized_package)
group = context['group']
--- a/ckan/model/meta.py Wed Jul 27 11:11:43 2011 +0100
+++ b/ckan/model/meta.py Wed Jul 27 13:53:14 2011 +0100
@@ -1,6 +1,7 @@
import datetime
"""SQLAlchemy Metadata and Session object"""
from sqlalchemy import MetaData, __version__ as sqav
+from sqlalchemy.orm import class_mapper
from sqlalchemy.orm import scoped_session, sessionmaker
import sqlalchemy.orm as orm
from sqlalchemy.orm.session import SessionExtension
@@ -37,42 +38,42 @@
revision = session.revision
except AttributeError:
return
-
new = obj_cache['new']
changed = obj_cache['changed']
deleted = obj_cache['deleted']
-
for obj in new | changed | deleted:
-
if not hasattr(obj, '__revision_class__'):
continue
-
revision_cls = obj.__revision_class__
-
+ revision_table = class_mapper(revision_cls).mapped_table
## when a normal active transaction happens
if 'pending' not in obj.state:
- revision.approved_timestamp = datetime.datetime.now()
- old = session.query(revision_cls).filter_by(
- current='1',
- id = obj.id
- ).first()
- if old:
- old.current = '0'
- session.add(old)
+ ### this is asql statement as we do not want it in object cache
+ session.execute(
+ revision_table.update().where(
+ and_(revision_table.c.id == obj.id,
+ revision_table.c.current == '1')
+ ).values(current='0')
+ )
q = session.query(revision_cls)
q = q.filter_by(expired_timestamp=datetime.datetime(9999, 12, 31), id=obj.id)
results = q.all()
-
for rev_obj in results:
+ values = {}
if rev_obj.revision_id == revision.id:
- rev_obj.revision_timestamp = revision.timestamp
+ values['revision_timestamp'] = revision.timestamp
if 'pending' not in obj.state:
- rev_obj.current = '1'
+ values['current'] = '1'
else:
- rev_obj.expired_id = revision.id
- rev_obj.expired_timestamp = revision.timestamp
- session.add(rev_obj)
+ values['expired_id'] = revision.id
+ values['expired_timestamp'] = revision.timestamp
+ session.execute(
+ revision_table.update().where(
+ and_(revision_table.c.id == rev_obj.id,
+ revision_table.c.revision_id == rev_obj.revision_id)
+ ).values(**values)
+ )
def after_commit(self, session):
if hasattr(session, '_object_cache'):
--- a/ckan/plugins/interfaces.py Wed Jul 27 11:11:43 2011 +0100
+++ b/ckan/plugins/interfaces.py Wed Jul 27 13:53:14 2011 +0100
@@ -10,7 +10,8 @@
'IMiddleware',
'IDomainObjectModification', 'IGroupController',
'IPackageController', 'IPluginObserver',
- 'IConfigurable', 'IConfigurer', 'IAuthorizer'
+ 'IConfigurable', 'IConfigurer', 'IAuthorizer',
+ 'IActions'
]
from inspect import isclass
@@ -300,4 +301,12 @@
other Authorizers to run; True will shortcircuit and return.
"""
-
+class IActions(Interface):
+ """
+ Allow adding of actions to the logic layer.
+ """
+ def get_actions(self):
+ """
+ Should return a dict, the keys being the name of the logic
+ function and the values being the functions themselves.
+ """
--- a/ckan/tests/functional/api/model/test_package.py Wed Jul 27 11:11:43 2011 +0100
+++ b/ckan/tests/functional/api/model/test_package.py Wed Jul 27 13:53:14 2011 +0100
@@ -48,6 +48,7 @@
# Check the value of the Location header.
location = res.header('Location')
+
assert offset in location
res = self.app.get(location, status=self.STATUS_200_OK)
# Check the database record.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/tests/functional/api/test_action.py Wed Jul 27 13:53:14 2011 +0100
@@ -0,0 +1,72 @@
+from ckan.lib.create_test_data import CreateTestData
+import ckan.model as model
+from ckan.tests import WsgiAppCase
+import json
+from pprint import pprint, pformat
+
+class TestAction(WsgiAppCase):
+
+ @classmethod
+ def setup_class(self):
+ CreateTestData.create()
+
+ @classmethod
+ def teardown_class(self):
+ model.repo.rebuild_db()
+
+ def test_01_package_list(self):
+ postparams = '%s=1' % json.dumps({})
+ res = self.app.post('/api/action/package_list', params=postparams)
+ assert json.loads(res.body) == {"help": "Lists the package by name",
+ "success": True,
+ "result": ["annakarenina", "warandpeace"]}
+
+ def test_02_create_update_package(self):
+
+ package = {
+ 'author': None,
+ 'author_email': None,
+ 'extras': [{'key': u'original media','value': u'"book"'}],
+ 'license_id': u'other-open',
+ 'maintainer': None,
+ 'maintainer_email': None,
+ 'name': u'annakareninanew',
+ 'notes': u'Some test now',
+ 'resources': [{'alt_url': u'alt123',
+ 'description': u'Full text.',
+ 'extras': {u'alt_url': u'alt123', u'size': u'123'},
+ 'format': u'plain text',
+ 'hash': u'abc123',
+ 'position': 0,
+ 'url': u'http://www.annakarenina.com/download/'},
+ {'alt_url': u'alt345',
+ 'description': u'Index of the novel',
+ 'extras': {u'alt_url': u'alt345', u'size': u'345'},
+ 'format': u'json',
+ 'hash': u'def456',
+ 'position': 1,
+ 'url': u'http://www.annakarenina.com/index.json'}],
+ 'tags': [{'name': u'russian'}, {'name': u'tolstoy'}],
+ 'title': u'A Novel By Tolstoy',
+ 'url': u'http://www.annakarenina.com',
+ 'version': u'0.7a'
+ }
+
+ wee = json.dumps(package)
+ postparams = '%s=1' % json.dumps(package)
+ res = self.app.post('/api/action/package_create', params=postparams,
+ extra_environ={'Authorization': 'tester'})
+ package_created = json.loads(res.body)['result']
+ print package_created
+ package_created['name'] = 'moo'
+ postparams = '%s=1' % json.dumps(package_created)
+ res = self.app.post('/api/action/package_update', params=postparams,
+ extra_environ={'Authorization': 'tester'})
+
+ package_updated = json.loads(res.body)['result']
+ package_updated.pop('revision_id')
+ package_updated.pop('revision_timestamp')
+ package_created.pop('revision_id')
+ package_created.pop('revision_timestamp')
+ assert package_updated == package_created#, (pformat(json.loads(res.body)), pformat(package_created['result']))
+
--- a/ckan/tests/lib/test_dictization.py Wed Jul 27 11:11:43 2011 +0100
+++ b/ckan/tests/lib/test_dictization.py Wed Jul 27 13:53:14 2011 +0100
@@ -516,9 +516,8 @@
anna1 = model.Session.query(model.Package).filter_by(name='annakarenina_changed2').one()
context = {"model": model,
"session": model.Session,
- 'user': 'testsysadmin',
- "id": anna1.id}
- make_latest_pending_package_active(context)
+ 'user': 'testsysadmin'}
+ make_latest_pending_package_active(context, {'id': anna1.id})
pkgrevisions = model.Session.query(model.PackageRevision).filter_by(id=anna1.id).all()
sorted_packages = sorted(pkgrevisions, key=lambda x:x.revision_timestamp)[::-1]
http://bitbucket.org/okfn/ckan/changeset/496c9ad4be73/
changeset: 496c9ad4be73
user: dread
date: 2011-07-28 17:17:08
summary: [tests][xs]: Tests were occasionally breaking when ordering of lists was changing, when this was not important to test.
affected #: 2 files (1.7 KB)
--- a/ckan/tests/functional/api/__init__.py Thu Jul 28 12:55:51 2011 +0100
+++ b/ckan/tests/functional/api/__init__.py Thu Jul 28 16:17:08 2011 +0100
@@ -0,0 +1,34 @@
+from nose.tools import assert_equal
+import copy
+
+def change_lists_to_sets(iterable):
+ '''recursive method to drill down into iterables to
+ convert any list or tuples into sets. Does not work
+ though for dictionaries in lists.'''
+ if isinstance(iterable, dict):
+ for key in iterable:
+ if isinstance(iterable[key], (list, tuple)):
+ try:
+ iterable[key] = set(iterable[key])
+ except TypeError:
+ # e.g. unhashable
+ pass
+ elif getattr(iterable[key], '__iter__', False):
+ change_lists_to_sets(iterable[key])
+ elif isinstance(iterable, (list, tuple)):
+ for item in iterable:
+ if isinstance(item, (list, tuple)):
+ iterable.pop(item)
+ iterable.append(set(item))
+ elif getattr(item, '__iter__', False):
+ change_lists_to_sets(item)
+ else:
+ raise NotImplementedError
+
+def assert_dicts_equal_ignoring_ordering(dict1, dict2):
+ '''Asserts dicts are equal, assuming that the ordering of
+ any lists is unimportant.'''
+ dicts = [copy.deepcopy(dict1), copy.deepcopy(dict2)]
+ for d in dicts:
+ d = change_lists_to_sets(d)
+ assert_equal(dicts[0], dicts[1])
--- a/ckan/tests/functional/api/test_action.py Thu Jul 28 12:55:51 2011 +0100
+++ b/ckan/tests/functional/api/test_action.py Thu Jul 28 16:17:08 2011 +0100
@@ -1,8 +1,10 @@
+import json
+from pprint import pprint, pformat
+
from ckan.lib.create_test_data import CreateTestData
import ckan.model as model
from ckan.tests import WsgiAppCase
-import json
-from pprint import pprint, pformat
+from ckan.tests.functional.api import assert_dicts_equal_ignoring_ordering, change_lists_to_sets
class TestAction(WsgiAppCase):
@@ -32,10 +34,12 @@
def test_01_package_list(self):
postparams = '%s=1' % json.dumps({})
res = self.app.post('/api/action/package_list', params=postparams)
- assert json.loads(res.body) == {"help": "Lists the package by name",
- "success": True,
- "result": ["annakarenina", "warandpeace"]}
-
+ assert_dicts_equal_ignoring_ordering(
+ json.loads(res.body),
+ {"help": "Lists the package by name",
+ "success": True,
+ "result": ["annakarenina", "warandpeace"]})
+
def test_02_package_autocomplete(self):
postparams = '%s=1' % json.dumps({'q':'a'})
res = self.app.post('/api/action/package_autocomplete', params=postparams)
@@ -122,19 +126,27 @@
def test_06_tag_list(self):
postparams = '%s=1' % json.dumps({})
res = self.app.post('/api/action/tag_list', params=postparams)
- assert json.loads(res.body) == {'help': 'Returns a list of tags',
- 'success': True,
- 'result': ['russian', 'tolstoy']}
+ assert_dicts_equal_ignoring_ordering(
+ json.loads(res.body),
+ {'help': 'Returns a list of tags',
+ 'success': True,
+ 'result': ['russian', 'tolstoy']})
#Get all fields
postparams = '%s=1' % json.dumps({'all_fields':True})
res = self.app.post('/api/action/tag_list', params=postparams)
res_obj = json.loads(res.body)
pprint(res_obj)
assert res_obj['success'] == True
- assert res_obj['result'][0]['name'] == 'russian'
- assert len(res_obj['result'][0]['packages']) == 3
- assert res_obj['result'][1]['name'] == 'tolstoy'
- assert len(res_obj['result'][1]['packages']) == 2
+ if res_obj['result'][0]['name'] == 'russian':
+ russian_index = 0
+ tolstoy_index = 1
+ else:
+ russian_index = 1
+ tolstoy_index = 0
+ assert res_obj['result'][russian_index]['name'] == 'russian'
+ assert len(res_obj['result'][russian_index]['packages']) - \
+ len(res_obj['result'][tolstoy_index]['packages']) == 1
+ assert res_obj['result'][tolstoy_index]['name'] == 'tolstoy'
assert 'id' in res_obj['result'][0]
assert 'id' in res_obj['result'][1]
@@ -294,14 +306,16 @@
postparams = '%s=1' % json.dumps({})
res = self.app.post('/api/action/group_list', params=postparams)
res_obj = json.loads(res.body)
- assert res_obj == {
- 'result': [
- 'david',
- 'roger'
- ],
- 'help': 'Returns a list of groups',
- 'success': True
- }
+ assert_dicts_equal_ignoring_ordering(
+ res_obj,
+ {
+ 'result': [
+ 'david',
+ 'roger'
+ ],
+ 'help': 'Returns a list of groups',
+ 'success': True
+ })
#Get all fields
postparams = '%s=1' % json.dumps({'all_fields':True})
http://bitbucket.org/okfn/ckan/changeset/18700b90220d/
changeset: 18700b90220d
user: dread
date: 2011-07-28 17:20:05
summary: [merge]
affected #: 1 file (614 bytes)
--- a/README.txt Thu Jul 28 16:17:08 2011 +0100
+++ b/README.txt Thu Jul 28 16:20:05 2011 +0100
@@ -102,35 +102,28 @@
pip install --ignore-installed -e hg+http://bitbucket.org/okfn/ckan#egg=ckan
- CKAN has a set of dependencies it requires which you should install too:
+ CKAN has dependent packages it requires you install. They are listed in the three pyenv/src/ckan/requires files.
- ::
-
- pip install --ignore-installed -r pyenv/src/ckan/requires/lucid_missing.txt -r pyenv/src/ckan/requires/lucid_conflict.txt
-
- The ``--ignore-installed`` option ensures ``pip`` installs software into
- this virtual environment even if it is already present on the system.
-
- If you are using Ubuntu Lucid you can install the rest of the dependencies
- from the system versions like this:
-
- ::
+ If you are running Ubuntu Lucid then it is recommended you take advantage of the Lucid packages to cover the dependencies listed in lucid_present.txt. In this case you should install the Lucid present packages::
sudo apt-get install python-psycopg2 python-lxml python-sphinx
sudo apt-get install python-pylons python-formalchemy python-repoze.who
sudo apt-get install python-repoze.who-plugins python-tempita python-zope.interface
- If you are not using Ubuntu Lucid you'll still need to install all the
- dependencies that would have been met in the ``apt-get install`` command
- at the start. You can do so like this:
+ And the remaining (non-Lucid) packages are installed like this::
- ::
+ pip install --ignore-installed -r pyenv/src/ckan/requires/lucid_missing.txt -r pyenv/src/ckan/requires/lucid_conflict.txt
- pip install --ignore-installed -r pyenv/src/ckan/requires/lucid_present.txt
+ If you are not using Ubuntu Lucid then should install all three sets of dependencies with this single command::
+
+ pip install --ignore-installed -r pyenv/src/ckan/requires/lucid_present.txt -r pyenv/src/ckan/requires/lucid_missing.txt -r pyenv/src/ckan/requires/lucid_conflict.txt
This will take a **long** time. Particularly the install of the ``lxml``
package.
+ The ``--ignore-installed`` option ensures ``pip`` installs software into
+ this virtual environment even if it is already present on the system. Because of this, to ensure you get a mutually agreeable version of WebOb installed, you shouldn't install each requirements file on its own with this option.
+
At this point you will need to deactivate and then re-activate your
virtual environment to ensure that all the scripts point to the correct
locations:
@@ -204,6 +197,10 @@
Other configuration, such as setting the language of the site or editing the
visual theme are described in :doc:`configuration` (doc/configuration.rst)
+ .. note ::
+
+ If the paster command gives you ``ImportError: cannot import name UnicodeMultiDict`` then you have gotten a version of WebOb that is too new for our Pylons. This usually occurs if you install Remove WebOb and reinstall version 1.0.8.
+
.. caution ::
Advanced users: If you are using CKAN's fab file capability you currently need to create
http://bitbucket.org/okfn/ckan/changeset/ea8a9bd5b8c4/
changeset: ea8a9bd5b8c4
user: dread
date: 2011-07-28 17:20:15
summary: [merge]
affected #: 1 file (1 byte)
--- a/ckan/controllers/package.py Thu Jul 28 16:20:05 2011 +0100
+++ b/ckan/controllers/package.py Thu Jul 28 16:20:15 2011 +0100
@@ -378,7 +378,7 @@
errors = errors or {}
vars = {'data': data, 'errors': errors, 'error_summary': error_summary}
- self._setup_template_variables(context, {'id':'id'})
+ self._setup_template_variables(context, {'id': id})
c.form = render(self.package_form, extra_vars=vars)
return render('package/edit.html')
Repository URL: https://bitbucket.org/okfn/ckan/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
More information about the ckan-changes
mailing list