This branch looks very nice Brad.
LGTM with changes. I added a lot of comments below, but they are mostly
minors/nice to have, except for some documentation requests, code
removal requests, and a possible string encoding problem. I will QA this
code when the changes are pushed later. Thank you!
https://codereview.appspot.com/26740043/diff/1/server/guiserver/bundles/__init__.py#newcode105
server/guiserver/bundles/__init__.py:105: parameter is optional in the
case YAML includes only one bundle.
Please document that the BundleID is completely optional, what that
value means, what it is used for and how it looks like (e.g. I guess it
must not start with "bundle:" because that's a bundle URL, but better
not to guess).
https://codereview.appspot.com/26740043/diff/1/server/guiserver/bundles/utils.py#newcode229
server/guiserver/bundles/utils.py:229: url =
'{}api/3/bundle/{}/{}'.format(charmworld_url, bundle_id, path)
Please check that bundle_id is a string. I suspect it's a unicode
string, so we should encode it to utf-8 here (so that it is not
implicitly ascii encoded) or make the whole url a unicode string. The
bundle id comes from the user and can be anything.
This branch looks very nice Brad.
LGTM with changes. I added a lot of comments below, but they are mostly
minors/nice to have, except for some documentation requests, code
removal requests, and a possible string encoding problem. I will QA this
code when the changes are pushed later. Thank you!
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ apps.py guiserver/ apps.py (right):
File server/
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ apps.py# newcode43 guiserver/ apps.py: 43: options. charmworldurl)
server/
It would be nice to expose the charmworld URL also in the
/gui-server-info InfoHandler. That's just a nice to have for another
card I guess.
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ __init_ _.py guiserver/ bundles/ __init_ _.py (right):
File server/
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ __init_ _.py#newcode99 guiserver/ bundles/ __init_ _.py:99: },
server/
In the other parts of this docstring, we aligned the closing brace of
the value with the key. <shrug>
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ __init_ _.py#newcode105 guiserver/ bundles/ __init_ _.py:105: parameter is optional in the
server/
case YAML includes only one bundle.
Please document that the BundleID is completely optional, what that
value means, what it is used for and how it looks like (e.g. I guess it
must not start with "bundle:" because that's a bundle URL, but better
not to guess).
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ base.py guiserver/ bundles/ base.py (right):
File server/
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ base.py# newcode99 guiserver/ bundles/ base.py: 99: self.bundle_ids = {}
server/
Is bundle_ids really required? ISTM it's not really used.
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ base.py# newcode125 guiserver/ bundles/ base.py: 125: def import_bundle(self, user, None):
server/
name, bundle, bundle_id, test_callback=
It would be nice to make bundle_id explicitly optional (i.e.
bundle_id=None here).
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ base.py# newcode159 guiserver/ bundles/ base.py: 159: self.bundle_ ids[deployment_ id] =
server/
bundle_id
AFAICT these two lines can be removed as well.
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ base.py# newcode190 guiserver/ bundles/ base.py: 190: # Increment the Charmworld
server/
deployment count upon successful
The count is increased also if the deployment failed. It seems ok to me,
but we should fix the comment.
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ base.py# newcode192 guiserver/ bundles/ base.py: 192: if bundle_id is not None:
server/
Nice and simple.
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ utils.py guiserver/ bundles/ utils.py (right):
File server/
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ utils.py# newcode25 guiserver/ bundles/ utils.py: 25: from tornado.httpclient import
server/
AsyncHTTPClient
Very very minor: could you please move this import after the "from
tornado import..." one? Or just add "httpclient" to the list below?
<shrug>
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ utils.py# newcode229 guiserver/ bundles/ utils.py: 229: url = 3/bundle/ {}/{}'. format( charmworld_ url, bundle_id, path)
server/
'{}api/
Please check that bundle_id is a string. I suspect it's a unicode
string, so we should encode it to utf-8 here (so that it is not
implicitly ascii encoded) or make the whole url a unicode string. The
bundle id comes from the user and can be anything.
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ utils.py# newcode237 guiserver/ bundles/ utils.py: 237: logging.error('URL: url.encode( 'utf-8' )). Otherwise 'URL: {!r}'.format(url).
server/
{}'.format(url))
If you decided to use a unicode url, then:
format(
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ utils.py# newcode238 guiserver/ bundles/ utils.py: 238: logging. error(' Exception: exc.message) ) exception( exc): this will print the full
server/
{}'.format(
IIRC you could also use logging.
traceback to the log file <shrug>.
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ utils.py# newcode240 guiserver/ bundles/ utils.py: 240: success = bool(resp.code == 200)
server/
Isn't resp.code == 200 already a bool? If you just wanted to be more
explicit, sounds good.
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ views.py guiserver/ bundles/ views.py (right):
File server/
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ views.py# newcode82 guiserver/ bundles/ views.py: 82: will be None if not given.
server/
Very nice.
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ bundles/ views.py# newcode136 guiserver/ bundles/ views.py: 136: request.user, name, bundle, id=bundle_ id.
server/
bundle_id)
As mentioned, this could be bundle_
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ tests/bundles/ test_base. py guiserver/ tests/bundles/ test_base. py (right):
File server/
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ tests/bundles/ test_base. py#newcode111 guiserver/ tests/bundles/ test_base. py:111: self.user, 'bundle',
server/
self.bundle, None,
If we make the import_bundle bundle_id parameter optional, all those
None values can be omitted, or we could pass them as kwargs, so that
it's more clear what the function requires.
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ tests/bundles/ test_utils. py guiserver/ tests/bundles/ test_utils. py (right):
File server/
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ tests/bundles/ test_utils. py#newcode450 guiserver/ tests/bundles/ test_utils. py:450: with mock_path) :
server/
mock.patch(
as mock_fetch...
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ tests/bundles/ test_utils. py#newcode451 guiserver/ tests/bundles/ test_utils. py:451: ok = yield _deployment_ counter( bundle_ id, None) e(mock_ fetch.called) ?
server/
utils.increment
self.assertFals
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ tests/bundles/ test_views. py guiserver/ tests/bundles/ test_views. py (right):
File server/
https:/ /codereview. appspot. com/26740043/ diff/1/ server/ guiserver/ tests/bundles/ test_views. py#newcode212 guiserver/ tests/bundles/ test_views. py:212: # The following tests validate_ import_ params directly.
server/
exercise views._
Thank you! ISTM that those three tests don't require @gen_test.
https:/ /codereview. appspot. com/26740043/