-
-
djblets/webapi/resources/mixins/extensions.py (Diff revision 1) Col: 1 E302 expected 2 blank lines, found 1
-
djblets/webapi/resources/mixins/extensions.py (Diff revision 1) Col: 80 E501 line too long (82 > 79 characters)
-
djblets/webapi/resources/mixins/extensions.py (Diff revision 1) Col: 1 W391 blank line at end of file
-
djblets/webapi/resources/root.py (Diff revision 1) Col: 69 E261 at least two spaces before inline comment
-
-
Providing URI templates for extensions
Review Request #8432 — Created Sept. 24, 2016 and submitted
This project adds uri templates for extensions to the api. Presently,
theRootResource
web API resource generates URI templates as
shortcuts to users. Extensions are able to provide their own API
resources, however they are not currently picked up by RootResource.
It has been confirmed that this isn't a caching bug. Instead,
RootResource needs to be modified to continue walking the tree upon
encountering an extension. Currently, the proposed solution is to
create a mixin class incorporating functionality from RootResource
to track signals from the ExtensionResource. The Review Board project
RootResource would inherit this new mixin accordingly.
Performed an HTTP request on
localhost:8080/api/
when no extensions are
installed and noted the absence of any extension templates in the response.Installed the checklist extension from rb-extension-pack and enabled
it on my local instance. Made a new HTTP request tolocalhost:8080/api/
and noted that the extension templates are now correctly included.
Disabling the extension removes the extensions.Ran djblets unit tests and noted all tests pass.
Adding new unit tests to verify functionality. All pass.
Description | From | Last Updated |
---|---|---|
test_extensionresourcemixin.py should be test_extension_resource_mixin.py. |
brennie | |
"Presently The" in your description should be "Presently the" |
brennie | |
I noticed your testing done mentions the httpie tool and the fact that the devserver is on port 8080. Can … |
brennie | |
"URI" in your summary. |
brennie | |
For the Description, "ReviewBoard" -> "Review Board". |
mike_conley | |
test_root_resource.py is missing a module docstring. |
chipx86 | |
Col: 1 E302 expected 2 blank lines, found 1 |
reviewbot | |
Col: 80 E501 line too long (82 > 79 characters) |
reviewbot | |
Col: 1 W391 blank line at end of file |
reviewbot | |
Col: 69 E261 at least two spaces before inline comment |
reviewbot | |
Col: 80 E501 line too long (88 > 79 characters) |
reviewbot | |
Col: 59 W292 no newline at end of file |
reviewbot | |
Col: 19 W292 no newline at end of file |
reviewbot | |
Col: 80 E501 line too long (81 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (82 > 79 characters) |
reviewbot | |
This will save you a lot of review changes. Blank line around blocks (like if, for, etc.). |
LA larmiej | |
Module imports go above symbol imports, so this should be like: import six from djblets.foo import bar... |
brennie | |
Missing a period. |
brennie | |
This should be the first line of the method, followed by a blank line. |
brennie | |
Col: 80 E501 line too long (83 > 79 characters) |
reviewbot | |
The comment should be a docstring. |
brennie | |
Missing docstring. |
brennie | |
Col: 1 E302 expected 2 blank lines, found 1 |
reviewbot | |
Mixins should inherit from object, otherwise it's just a subclass. The idea is that a mixin is a very small, … |
chipx86 | |
I know this is a WIP change, but for here and other docstrings, make sure to follow the requirements in … |
chipx86 | |
This should be at the top of the file. |
chipx86 | |
With my comments further down, you won't need to clear this. Same in _remove_extension_urls_from_template. |
chipx86 | |
This should just be a keyword argument in the method definition. Same further down. |
chipx86 | |
Blank line between these (between code and blocks like if/for). |
chipx86 | |
We use Django's version of six: from django.utils import six Note also that six (and Django's version) is a third-party … |
chipx86 | |
Should be 2 blank lines. |
chipx86 | |
Yep, this will need to be extracted, but there's another thing that's important to note as well. As currently written, … |
chipx86 | |
Col: 49 E127 continuation line over-indented for visual indent |
reviewbot | |
__init__ for a subclass/mixin MUST call the superclass __init__ method, in this case: super(ExtensionRootResourceMixin, self).__init__() |
brennie | |
Col: 80 E501 line too long (85 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (81 > 79 characters) |
reviewbot | |
Col: 33 E126 continuation line over-indented for hanging indent |
reviewbot | |
Col: 71 W292 no newline at end of file |
reviewbot | |
Col: 49 E127 continuation line over-indented for visual indent |
reviewbot | |
Col: 80 E501 line too long (85 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (81 > 79 characters) |
reviewbot | |
Col: 33 E126 continuation line over-indented for hanging indent |
reviewbot | |
Col: 71 W292 no newline at end of file |
reviewbot | |
Col: 49 E127 continuation line over-indented for visual indent |
reviewbot | |
Col: 80 E501 line too long (85 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (81 > 79 characters) |
reviewbot | |
'ipdb' imported but unused |
reviewbot | |
Col: 80 E501 line too long (88 > 79 characters) |
reviewbot | |
Col: 56 E261 at least two spaces before inline comment |
reviewbot | |
Col: 33 E126 continuation line over-indented for hanging indent |
reviewbot | |
Col: 71 W292 no newline at end of file |
reviewbot | |
Col: 49 E127 continuation line over-indented for visual indent |
reviewbot | |
Col: 80 E501 line too long (85 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (81 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (83 > 79 characters) |
reviewbot | |
Col: 51 E261 at least two spaces before inline comment |
reviewbot | |
Col: 33 E126 continuation line over-indented for hanging indent |
reviewbot | |
Col: 12 E713 test for membership should be 'not in' |
reviewbot | |
Col: 12 E713 test for membership should be 'not in' |
reviewbot | |
Col: 49 E127 continuation line over-indented for visual indent |
reviewbot | |
Col: 80 E501 line too long (85 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (81 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (83 > 79 characters) |
reviewbot | |
Col: 51 E261 at least two spaces before inline comment |
reviewbot | |
Col: 33 E126 continuation line over-indented for hanging indent |
reviewbot | |
Col: 5 E303 too many blank lines (2) |
reviewbot | |
You can do :py:class:djblets.resources.whatever.RootResource and it will link to the root resource documentation |
brennie | |
Missing docstring. |
brennie | |
I don't think this tells us anything. |
brennie | |
No blank line here. |
brennie | |
This is pretty unweildly. I think it would be better to pull this out into a variable and iterate over … |
brennie | |
This should be '%s%s' % (href, registered_href). Generally, you'll want to avoid string concatenation in Python because it is slow. … |
brennie | |
"Yield" Docstrings for methods should always be written in the imperative mood, i.e., they tell (or command) you what to … |
brennie | |
Missing Args and Yields Yields is just like Returns. |
brennie | |
Again, you'll want to use %-formatting here, as this will create a temporary string (object_href + child.uri_name) and then create … |
brennie | |
Missing Args. |
brennie | |
Here, too. |
brennie | |
The first import should be: from __future__ import unicode_literals This turns all 'string's into u'string's automatically. The str (default for … |
brennie | |
'ExtensionResource' imported but unused |
reviewbot | |
Docstring. |
brennie | |
Missing tests. |
brennie | |
Docstring. This should be something like """Unit tests for root resource template registration.""" |
brennie | |
Please don't use mock.Mock. Create a dummy class that has all the stuff you need. mock is a huge dependency … |
brennie | |
Col: 13 E122 continuation line missing indentation or outdented |
reviewbot | |
Col: 80 E501 line too long (89 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (91 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (85 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (91 > 79 characters) |
reviewbot | |
"URI template cache" |
brennie | |
Col: 80 E501 line too long (92 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (92 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (89 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (92 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (92 > 79 characters) |
reviewbot | |
Col: 68 W292 no newline at end of file |
reviewbot | |
Additionally, docstrings should be of the form: """Single line summary. Multi-line description. """ You may want to cut out the … |
brennie | |
This should line up with the first ". |
brennie | |
Same here. |
brennie | |
Docstrings should be in the imperitive moode ("Generate"). Missing Args, Returns blocks |
brennie | |
And here, too. |
brennie | |
And here. Probably want to re-word this to be something like """Return the associated extension resource.""" |
brennie | |
Since this is soo long, you'll probably want to pull out the six.iteritems bit into resource_templates. |
brennie | |
Backslashes are icky and can lead to bugs when there is trailing whitespace that accidentally committed, so we tend to … |
brennie | |
unicode. |
brennie | |
This actually yields a tuple. However, I feel you'll want to use a namedtuple here. Somewhere above in this file … |
brennie | |
Can we pull self.walk_resources(child, child_href) into a variable and iterate over that instead? |
brennie | |
Pull this out, too. |
brennie | |
Imperitive mood ("Register") |
brennie | |
unicode. |
brennie | |
unicode |
brennie | |
"Unregister" This may not be a word, but what do dictionaries know? They let frobnicate be a word :) |
brennie | |
unicode |
brennie | |
Not really necessary tbh. |
brennie | |
"""Unit tests for the ExtensionRootResourceMixin.""" No need for full class paths here. |
brennie | |
setUp must call super(ExtensionTemplateTests, self).setUp() or you're going to end up with weird, unsolvable test failures sometimes :) |
brennie | |
Docstrings should be of the form: """Single line summary. Multi-line description. """ See my comment on the ExtensionTemplateTests for what … |
brennie | |
setUp must call super(RootResourceTemplateRegistrationTests, self).setUp() or you're going to end up with weird, unsolvable test failures sometimes :) |
brennie | |
No blank line here. |
brennie | |
Pull this out to a top level element, otherwise we are creating a new class each test pass. If you … |
brennie | |
Col: 13 E122 continuation line missing indentation or outdented |
reviewbot | |
Col: 80 E501 line too long (89 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (80 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (91 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (85 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (91 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (92 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (92 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (89 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (92 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (92 > 79 characters) |
reviewbot | |
Col: 55 E201 whitespace after '(' |
reviewbot | |
Col: 51 E202 whitespace before ')' |
reviewbot | |
'SpyAgency' imported but unused |
reviewbot | |
Col: 80 E501 line too long (87 > 79 characters) |
reviewbot | |
Col: 30 E126 continuation line over-indented for hanging indent |
reviewbot | |
Blank line between these. |
brennie | |
Missing Args |
brennie | |
Missing **kwargs (dict) Also, what is kwargs used for here? |
brennie | |
Since this isnt a type object, can we rename this to ext or extension? |
brennie | |
Since walk_resources returns the namedtuple instance and we're not using all the fields we can do: for entry in self.walk_resources(resource, … |
brennie | |
Can we pull out self.get_extension_resource() into a variable at the top of the function and reuse it in each iteration? |
brennie | |
Same here re: kwargs. |
brennie | |
Same here. |
brennie | |
This will fit on one line. |
brennie | |
Reformat as: self.register_uri_template(entry.name, entry.list_href, ext_resource) |
brennie | |
Same thing here. |
brennie | |
Here, too. |
brennie | |
This will fit on one line |
brennie | |
This will fit on one line. |
brennie | |
Python standard libraries go in between __future__ imports and 3rd party imports (like django and djblets). |
brennie | |
"Attributes". |
brennie | |
Can you reformat this as: #: Attributes #: field (type): #: Description of field... #: #: field (type): #: Description … |
brennie | |
This should actually be the full type, i.e. djblets.webapi.responses.WebAPIResponseError. |
brennie | |
djblets.webapi.resources.base.WebAPIResource |
brennie | |
"Whether or not the resource is a list resource." |
brennie | |
Col: 55 E201 whitespace after '(' |
reviewbot | |
Col: 51 E202 whitespace before ')' |
reviewbot | |
Blank line between these. |
brennie | |
Could you reformat this as: templates[registered_name] = ( '%s%s' % (href, registered_href) ) |
brennie | |
This should yield self.ResourceEntry(resource.name_plural, list_href, resource, True). |
brennie | |
This should yield self.ResourceEntry(name, list_href, resource, is_list). |
brennie | |
And here |
brennie | |
And here. |
brennie | |
Reformat as: yield self.ResourceEntry(resource.name, object_href, resource, False) |
brennie | |
This can be simplified to: for entry in self.walk_resources(child, child_href): yield entry |
brennie | |
Can we rename this relative_path |
brennie | |
Can we name this relative_resource or parent_resource? |
brennie | |
Blank line between these. |
brennie | |
Again, can we rename this relative_resource or parent_resource? |
brennie | |
Reformat as: self._registered_uri_templates[relative_resource][name] = \ relative_path |
brennie | |
Docstrings for all these |
brennie | |
Can we call this TestChildResourceOne |
brennie | |
TestChildResourceTwo |
brennie | |
TestResourceOne |
brennie | |
TestResourceTwo |
brennie | |
TestExtension |
brennie | |
TestRootResource |
brennie | |
Docstrings should be of the form """Single line summary. Multi-line description. """ |
brennie | |
Rename to expected_result, actual_result. Also, I think this would be better formatted as the following: expected_result = { 'extension': 'http://testserver/{extension_name}/', … |
brennie | |
Col: 80 E501 line too long (81 > 79 characters) |
reviewbot | |
Add a trailing comma. |
brennie | |
Col: 80 E501 line too long (81 > 79 characters) |
reviewbot | |
Docstrings should be of the form """Single line summary. Multi-line description. """ |
brennie | |
You should be providing the extension resource to this, e.g. self.ext_mgr = ExtensionManager('') self.ext_resource = ExtensionResource(self.ext_mgr) self.root_resource = RootResource([ext_resource]) |
brennie | |
Can we just call these .ext_mgr and .extension? |
brennie | |
Reformat this as: self.root_resource._registered_uri_templates = { None: {'extension-1': '/first/'}, self.mock_extension: { 'extensions': 'http://localhost:8080/api/extensions/', }, } Also, isn't this backwards? Shouldn't … |
brennie | |
Rename as actual_result, expected_result ? |
brennie | |
Reformat this as: self.root_resource._uri_templates = { 'key1': 'value', 'key2': 'value', } |
brennie | |
Rename as expected_result, actual_result? |
brennie | |
This should be formatted as: self.assertFalse(self.root_resource._registered_uri_tempaltes[ self.mock_extension]) |
brennie | |
Col: 30 E126 continuation line over-indented for hanging indent |
reviewbot | |
Reformat this as: self.root_resource._uri_templates = { 'key1': 'value', 'key2': 'value', } |
brennie | |
Reformat this as: self.root_resource._uri_templates = { 'key1': 'value', 'key2': 'value', } |
brennie | |
Can you make a note that the subclass that uses this mixin must implement this? |
brennie | |
How about: for name, href in six.iteritems(unassigned_templates): # .... |
brennie | |
for entry in self.walk_resources(self, base_href): |
brennie | |
How about: if is_list: list_templates = self._registered_uri_templates.get( resource, {}) for name, href in six.iteritems(list_templates): templates[name] = ( '%s%s' % (entry.href, … |
brennie | |
This can be simplified to for entry in self.walk_resources(child, child_href): yield entry |
brennie | |
for entry in self.walk_resources(child, child_href): yield entry |
brennie | |
This doesn't really describe this properly. I would say it's a mixin for root resources that make use of ExtensionResource. … |
chipx86 | |
Blank line between these. |
chipx86 | |
This is missing **kwargs. |
chipx86 | |
The type needs to be a full class path. |
chipx86 | |
Same comments as above. |
chipx86 | |
This is missing a "Returns" block that states the return type and content. |
chipx86 | |
This should be on the same line. |
chipx86 | |
Same line. |
chipx86 | |
This can be one line. |
chipx86 | |
Indentation level for "Args" and "Yields" is wrong. |
chipx86 | |
ResourceEntry needs to: 1) Be on the next line 2) Be RootResource.ResourceEntry (these need to be either absolute paths, if … |
chipx86 | |
Let's construct all these with keyword arguments instead of positional arguments for the values. |
chipx86 | |
This should remain one statement. |
chipx86 | |
Same comment as above for keyword arguments. |
chipx86 | |
"URI" |
chipx86 | |
_registered_uri_templates and _uri_templates are implementation details. Docs should focus on a higher level saying what this does, not how it … |
chipx86 | |
This should say what it's relative to. |
chipx86 | |
Needs to be an absolute class path. Should also include , optional after the type. |
chipx86 | |
You can simplify much of this and reduce dictionary accesses: templates = self._registered_uri_templates.setdefault(relative_resource, {}) templates[name] = relative_path |
chipx86 | |
These are pretty conflicting statements. The second overrides the first. |
chipx86 | |
"URI" |
chipx86 | |
Same as above with the doc content. It should be higher level than what internal fields are being modified. |
chipx86 | |
Full class path and , optional. |
chipx86 | |
"URI" |
chipx86 | |
Better to do: try: del self._registered_uri_templates[relative_resource][name] except KeyError: pass This does two things: 1) Doesn't fail (like the current code) … |
chipx86 | |
Blank line between these. Djblets is the current project, and so has its own import group. |
chipx86 | |
These can be one import statement. |
chipx86 | |
Please use numbers instead of spelling them out for these classes. |
chipx86 | |
Missing a trailing period. Same with the ones below. |
chipx86 | |
This isn't in the proper form. It should be: """ ... Returns djblets.extensions.resources.ExtensionResource <description here> """ That said, these are … |
chipx86 | |
This should probably be ExtensionRootResourceMixinTests. |
chipx86 | |
This should be done first, probably. Blank line between it and the setters. |
chipx86 | |
So two things: 1) When testing a method, the docstring needs to list the class name and the proper name … |
chipx86 | |
This whole thing should be used inline below, like: self.assertEqual( actual_result, { ... }) |
chipx86 | |
Should just use assertEqual, not assert*Equal methods. Also, flip these. Thing you're testing should be first. Expected value second. Same … |
chipx86 | |
This should also be inline below. Same with other tests. |
chipx86 | |
This should be RootResourceTests, and should live in its own file (test_root_resource.py). |
chipx86 | |
Consistency is good. Both of these should look the same: .... = { self.ext_resource: { 'extensions': ..., }, None: { … |
chipx86 | |
This can be one line. Should ideally use keyword arguments, which would push to two lines, but they should start … |
chipx86 | |
This can be one line. |
chipx86 | |
These calls will read better if you use keyword arguments. |
chipx86 | |
Should be inline. |
chipx86 | |
Condense this. |
chipx86 | |
Col: 50 E225 missing whitespace around operator |
reviewbot | |
Col: 9 E303 too many blank lines (2) |
reviewbot | |
This is not a class, it is an instance (isn't it?) Rename this to ext or extension. If it is … |
brennie | |
"the URI templates." |
brennie | |
Same here. |
brennie | |
"the URI templates." |
brennie | |
Blank line between these. |
brennie | |
Can you change this to be a @classmethod ? e.g. @classmethod def walk_resources(cls, resource, list_href): and replace all usages of … |
brennie | |
Please elaborate on this. |
brennie | |
Don't wrap this. You will get a error from review bot but you can drop it. |
brennie | |
Blank line between these |
brennie | |
I actually don't think we normally document *args and **kwargs, since I often think that it's for passing through arguments … |
mike_conley | |
This is an interesting documentation style choice, the #:. Can you explain why you made that choice? I'm not familiar … |
mike_conley | |
Leftovers? |
mike_conley | |
Col: 80 E501 line too long (89 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (89 > 79 characters) |
reviewbot | |
This (and all other references to djblets.extensions.Extension) needs to be djblets.extensions.extension.Extension). The former doesn't exist, and only the latter will … |
chipx86 | |
Public methods must come before private method. This should be right after __init__. |
chipx86 | |
No parens. |
chipx86 | |
No outer parens needed. |
chipx86 | |
Col: 80 E501 line too long (89 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (89 > 79 characters) |
reviewbot | |
No parens. |
chipx86 | |
This is indented one level too far. |
chipx86 | |
Col: 80 E501 line too long (89 > 79 characters) |
reviewbot | |
Can you add a comment here just saying that we're clearing the cache so that future lookups will take into … |
chipx86 | |
Missing trailing period. All comments should be in full sentence format. |
chipx86 | |
Col: 80 E501 line too long (89 > 79 characters) |
reviewbot | |
Same comment here as above with a comment. |
chipx86 | |
Same here. |
chipx86 | |
This doesn't need to be a raw string. |
brennie | |
Again, this doesn't need to be a raw string. |
brennie | |
Col: 80 E501 line too long (89 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (89 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (89 > 79 characters) |
reviewbot | |
Col: 80 E501 line too long (89 > 79 characters) |
reviewbot | |
E501 line too long (89 > 79 characters) |
reviewbot | |
E501 line too long (89 > 79 characters) |
reviewbot |
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 2 (+31) |
-
Tool: Pyflakes Processed Files: djblets/webapi/resources/root.py djblets/webapi/resources/mixins/extensions.py Tool: PEP8 Style Checker Processed Files: djblets/webapi/resources/root.py djblets/webapi/resources/mixins/extensions.py
-
djblets/webapi/resources/mixins/extensions.py (Diff revision 2) Col: 19 W292 no newline at end of file
-
-
-
-
djblets/webapi/resources/root.py (Diff revision 2) This will save you a lot of review changes.
Blank line around blocks (like if, for, etc.).
Change Summary:
Fully functional prototyping done. Next step will be to extract this code in RootResource to the Mixin class discussed during the code sprint. Will also need to investigate a means for testing.
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 3 (+35) |
-
Tool: PEP8 Style Checker Processed Files: djblets/webapi/resources/root.py djblets/webapi/resources/mixins/extensions.py Tool: Pyflakes Processed Files: djblets/webapi/resources/root.py djblets/webapi/resources/mixins/extensions.py
-
-
-
djblets/webapi/resources/root.py (Diff revision 3) Module imports go above symbol imports, so this should be like:
import six from djblets.foo import bar...
-
-
djblets/webapi/resources/root.py (Diff revision 3) This should be the first line of the method, followed by a blank line.
-
-
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 4 (+49 -4) |
-
Tool: Pyflakes Processed Files: djblets/extensions/resources.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/extensions/resources.py djblets/webapi/resources/root.py
-
-
This looks like a good start! There are some things that will need to change though.
I cover how mixins and inheritence work below, along with some tips on docstrings and some other Pythonisms to be aware of (less important for a WIP, but worth getting in the habit of sooner rather than later).
There are some bigger topics involving how URIs are computed and how the classes relate, and we'll need to go over that. I cover it further below.
-
djblets/extensions/resources.py (Diff revision 4) Mixins should inherit from
object
, otherwise it's just a subclass.The idea is that a mixin is a very small, tight piece of code with (ideally) no parents, allowing other subclasses to include them without enforcing a particular parent class, which may not be desired.
As part of that contract, consumers of the mixin do have to inherit from a suitable parent (
RootResource
), but are free to choose which they want to use (some hypotheticalSuperAwesomeRootResource
would suffice, for instance). -
djblets/extensions/resources.py (Diff revision 4) I know this is a WIP change, but for here and other docstrings, make sure to follow the requirements in this guide by the time it's out of WIP:
https://www.reviewboard.org/docs/codebase/dev/docs/writing-codebase-docs/
-
-
djblets/extensions/resources.py (Diff revision 4) With my comments further down, you won't need to clear this. Same in
_remove_extension_urls_from_template
. -
djblets/extensions/resources.py (Diff revision 4) This should just be a keyword argument in the method definition. Same further down.
-
djblets/extensions/resources.py (Diff revision 4) Blank line between these (between code and blocks like if/for).
-
djblets/webapi/resources/root.py (Diff revision 4) We use Django's version of
six
:from django.utils import six
Note also that
six
(and Django's version) is a third-party module, not a Python stdlib module, so it shouldn't go in the stdlib import group. -
-
djblets/webapi/resources/root.py (Diff revision 4) Yep, this will need to be extracted, but there's another thing that's important to note as well. As currently written, it appears that the URI templates will end using something like
/api/myextension.Extension/myresource/
for the URI template, which wouldn't be correct. Rather, it should be/api/extensions/myextension.Extension/myresource/
(or/s/my-site/api/extensions/myextension.Extension/myresource/
for Local Sites). The parent (/api/extensions/
) depends on how the consumer has things set up.So there's a couple things that need to be solved here:
1) We need a clean way of registering URI templates from the mixin without clearing dictionaries e from therand without
RootResource
knowing it's going to be modified by a mixin in some way (_incomplete_uri_templates
).2) We need a way to inject these particular URI templates at the right level.
For #1...
I propose adding two new methods to
RootResource
:register_uri_template(name, rel_path)
andunregister_uri_template(name)
.These would operate off of
_incomplete_uri_templates
, allowing that to stay internal. (I would maybe rename that at this point to_registered_uri_templates
). Registering/unregistering would update this dictionary, and clearself._uri_templates
to ensure the old cache isn't used.For #2...
We need to be able to generate the right path to the
/api/extensions/
instance without knowing where that's going to be, and withoutRootResource
knowing anything about it, but we can't easily figure out that path in the extension signal handlers because we don't have arequest
(which we need in order to get the right path). Tricky!The best place to compute that path is in
RootResource
(since it's dealing with arequest
, without it explicitly knowing aboutExtensionResource
, and supporting maybe other scenarios like this in the future with other specialized resources.What I propose there is to take our shiny new methods and add a new optional keyword argument:
relative_to_resource=
. This would default toNone
, but could take a resource instance (likeresources.extension
from Review Board). So like:def register_uri_template(name, rel_path, relative_to_resource=None): ...
That dictionary of registered URI templates would be keyed off by the parent resource (None or an instance), rather than the extension ID like it is now. For example, printing it could look something like:
_registered_uri_templates = { None: { 'my-resource': '/blahblah/some-resource', ... }, resources.extension: { 'my-extension-resource': '/myextension.Extension/myresource/', ... }, ... }
You'd then have
walk_resources
include 2 more things in itsyield
statements:resource
, and a bool indicating if it's a list resource being yielded.Then,
get_uri_templates
can do:for registered_name, registered_href in six.iteritems(self._registered_uri_templates.get(None, [])): templates[registered_name] = registered_href for name, href, resource, is_list in self.walk_resources(self, base_href): templates[name] = href if is_list: for registered_name, registered_href in six.iteritems(self._registered_uri_templates.get(resource, [])): templates[registered_name] = href + registered_href
That should cleanly allow callers to register new URI templates at either the root level or relative to any other resource, without knowing where they are in the tree.
RootResource
does the work of figuring that out and building the URLs correctly.Mixin and ExtensionResource
There is one last part that needs to then be solved: The mixin needs to know about the
ExtensionResource
instance, but remember, Review Board creates that, not Djblets!To solve that, the mixin's contract with its consumer could be that the consumer must override a method:
get_extension_resource
. This would return theresources.extension
instance (in the case of Review Board), allowing the mixin to simply call that onself
and pass the result as the value torelative_to_resource=
.The mixin would provide a default that raises
NotImplementedError
. You can find other examples where we do this.I know that's a lot! But I think this gives us everything we need, and keeps the separation at the right levels.
Change Summary:
I've addressed Christian's review comments - however I've caught a bit of a snag in that making http requests to the development server doesn't seem to be updating my template list anymore. While I investigate I thought I'd take the chance to show my progress.
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 5 (+93 -8) |
-
Tool: PEP8 Style Checker Processed Files: djblets/extensions/resources.py djblets/webapi/resources/root.py Tool: Pyflakes Processed Files: djblets/extensions/resources.py djblets/webapi/resources/root.py
-
djblets/extensions/resources.py (Diff revision 5) Col: 49 E127 continuation line over-indented for visual indent
-
-
-
djblets/webapi/resources/root.py (Diff revision 5) Col: 33 E126 continuation line over-indented for hanging indent
-
-
-
djblets/extensions/resources.py (Diff revision 5) __init__
for a subclass/mixin MUST call the superclass__init__
method, in this case:super(ExtensionRootResourceMixin, self).__init__()
Change Summary:
Since refactoring to a mixin, the signal code for _generate_extension_uris_for_template/_remove_extension_uris_from_template is no longer executing when adding an extension. I've added print statements for debugging purposes.
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 6 (+96 -8) |
-
Tool: Pyflakes Processed Files: djblets/extensions/resources.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/extensions/resources.py djblets/webapi/resources/root.py
-
djblets/extensions/resources.py (Diff revision 6) Col: 49 E127 continuation line over-indented for visual indent
-
-
-
djblets/webapi/resources/root.py (Diff revision 6) Col: 33 E126 continuation line over-indented for hanging indent
-
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 7 (+109 -15) |
-
Tool: Pyflakes Processed Files: djblets/webapi/resources/base.py djblets/extensions/resources.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/webapi/resources/base.py djblets/extensions/resources.py djblets/webapi/resources/root.py
-
djblets/extensions/resources.py (Diff revision 7) Col: 49 E127 continuation line over-indented for visual indent
-
-
-
-
-
djblets/webapi/resources/base.py (Diff revision 7) Col: 56 E261 at least two spaces before inline comment
-
djblets/webapi/resources/root.py (Diff revision 7) Col: 33 E126 continuation line over-indented for hanging indent
-
Change Summary:
registered_uri_templates is now populating correctly - the final step to getting this refactoring operational again will be to modify
get_uri_templates
to correctly add the URIs of extensions.
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 8 (+111 -15) |
-
Tool: Pyflakes Processed Files: djblets/webapi/resources/base.py djblets/extensions/resources.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/webapi/resources/base.py djblets/extensions/resources.py djblets/webapi/resources/root.py
-
djblets/extensions/resources.py (Diff revision 8) Col: 49 E127 continuation line over-indented for visual indent
-
-
-
-
djblets/webapi/resources/base.py (Diff revision 8) Col: 51 E261 at least two spaces before inline comment
-
djblets/webapi/resources/root.py (Diff revision 8) Col: 33 E126 continuation line over-indented for hanging indent
-
djblets/webapi/resources/root.py (Diff revision 8) Col: 12 E713 test for membership should be 'not in'
-
djblets/webapi/resources/root.py (Diff revision 8) Col: 12 E713 test for membership should be 'not in'
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 9 (+117 -16) |
-
Tool: Pyflakes Processed Files: djblets/webapi/resources/base.py djblets/extensions/resources.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/webapi/resources/base.py djblets/extensions/resources.py djblets/webapi/resources/root.py
-
djblets/extensions/resources.py (Diff revision 9) Col: 49 E127 continuation line over-indented for visual indent
-
-
-
-
djblets/webapi/resources/base.py (Diff revision 9) Col: 51 E261 at least two spaces before inline comment
-
djblets/webapi/resources/root.py (Diff revision 9) Col: 33 E126 continuation line over-indented for hanging indent
-
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 10 (+95 -9) |
-
Tool: Pyflakes Processed Files: djblets/extensions/resources.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/extensions/resources.py djblets/webapi/resources/root.py
Change Summary:
Refactoring of RootResource to mixin complete. Currently investigating unit tests.
Summary: |
|
|||||||||
---|---|---|---|---|---|---|---|---|---|---|
Testing Done: |
|
Change Summary:
Added tests to previous review.
Testing Done: |
|
|||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Commit: |
|
|||||||||||||||||||||||||||||||||||||||
Diff: |
Revision 11 (+167 -9) |
-
Tool: Pyflakes Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extensionresourcemixin.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extensionresourcemixin.py djblets/webapi/resources/root.py
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) 'ExtensionResource' imported but unused
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) Col: 13 E122 continuation line missing indentation or outdented
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) Col: 80 E501 line too long (89 > 79 characters)
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) Col: 80 E501 line too long (91 > 79 characters)
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) Col: 80 E501 line too long (85 > 79 characters)
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) Col: 80 E501 line too long (91 > 79 characters)
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) Col: 80 E501 line too long (92 > 79 characters)
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) Col: 80 E501 line too long (92 > 79 characters)
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) Col: 80 E501 line too long (89 > 79 characters)
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) Col: 80 E501 line too long (92 > 79 characters)
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) Col: 80 E501 line too long (92 > 79 characters)
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) Col: 68 W292 no newline at end of file
-
-
-
djblets/extensions/resources.py (Diff revision 11) You can do :py:class:
djblets.resources.whatever.RootResource
and it will link to the root resource documentation -
-
-
-
djblets/webapi/resources/root.py (Diff revision 11) This could also be:
template.extend({ registered_name: '%s%s' % (href, registered_href), for registered_name, registered_href in six.iteritems( self._registered_uri_templates.get(resource, {}) ) })
Though I'm not sure if I prefer that over the loop. Not an issue, just a consideration.
-
djblets/webapi/resources/root.py (Diff revision 11) This is pretty unweildly. I think it would be better to pull this out into a variable and iterate over
six.iteritems(foo)
instead.(Generally we discourage multi-line for expressions because they become rather unreadable.)
-
djblets/webapi/resources/root.py (Diff revision 11) This should be
'%s%s' % (href, registered_href)
.Generally, you'll want to avoid string concatenation in Python because it is slow. Like, super slow. Using
%
-formatting will result in fewer allocations. -
djblets/webapi/resources/root.py (Diff revision 11) A multiline dosctring would be
"""Long description. """
without the blank line. However, you'll need the blank line given you also need args/yields.
-
djblets/webapi/resources/root.py (Diff revision 11) "Yield"
Docstrings for methods should always be written in the imperative mood, i.e., they tell (or command) you what to do rather than describe what it is going to do. "Shut the door" (imperitive) vs "Shuts the door" (non-imperitive).
-
djblets/webapi/resources/root.py (Diff revision 11) Missing
Args
andYields
Yields
is just likeReturns
. -
djblets/webapi/resources/root.py (Diff revision 11) Again, you'll want to use
%
-formatting here, as this will create a temporary string (object_href + child.uri_name
) and then create a final string which is the result. -
-
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) The first import should be:
from __future__ import unicode_literals
This turns all
'string'
s intou'string'
s automatically. Thestr
(default for strings withoutunicode_literals
) is actually a binary type and will cause encoding headaches.Aside: if you ever want to use a binary string (
str
) literal, you can useb'foo'
).This file will also need a docstring, e.g.
"""Unit tests for the classname mixin."""
-
-
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) Docstring. This should be something like
"""Unit tests for root resource template registration."""
-
djblets/webapi/tests/test_extensionresourcemixin.py (Diff revision 11) Please don't use
mock.Mock
. Create a dummy class that has all the stuff you need.mock
is a huge dependency and we're trying to get rid of it. -
Change Summary:
Addressing comments from @brennie.
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 12 (+230 -10) |
-
Tool: Pyflakes Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) Col: 13 E122 continuation line missing indentation or outdented
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) Col: 80 E501 line too long (89 > 79 characters)
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) Col: 80 E501 line too long (80 > 79 characters)
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) Col: 80 E501 line too long (91 > 79 characters)
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) Col: 80 E501 line too long (85 > 79 characters)
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) Col: 80 E501 line too long (91 > 79 characters)
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) Col: 80 E501 line too long (92 > 79 characters)
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) Col: 80 E501 line too long (92 > 79 characters)
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) Col: 80 E501 line too long (89 > 79 characters)
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) Col: 80 E501 line too long (92 > 79 characters)
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) Col: 80 E501 line too long (92 > 79 characters)
-
Make sure to drop/mark as fixed old issues from review bot. they just clutter up the review request issue table if theyre out of date.
-
djblets/extensions/resources.py (Diff revision 12) Additionally, docstrings should be of the form:
"""Single line summary. Multi-line description. """
You may want to cut out the
:py:class:
ref or move it into the description so you have an easier time fitting stuff in the summary.You can also do:
"""... .. seealso: :py:class:`~djblets.webapi.resources.root.RootResource` """
We use Sphinx for our documentation formatting. Here's a cheat sheet.
-
-
-
djblets/extensions/resources.py (Diff revision 12) Docstrings should be in the imperitive moode ("Generate").
Missing Args, Returns blocks
-
-
djblets/extensions/resources.py (Diff revision 12) And here.
Probably want to re-word this to be something like
"""Return the associated extension resource."""
-
djblets/webapi/resources/root.py (Diff revision 12) Since this is soo long, you'll probably want to pull out the
six.iteritems
bit intoresource_templates
. -
djblets/webapi/resources/root.py (Diff revision 12) Backslashes are icky and can lead to bugs when there is trailing whitespace that accidentally committed, so we tend to avoid them when it makes sense to do so. In this case, consider:
templates[registered_name] = ( '%s%s' % (href, registered_href) )
-
-
djblets/webapi/resources/root.py (Diff revision 12) This actually yields a tuple. However, I feel you'll want to use a
namedtuple
here.Somewhere above in this file you'll want to define a tuple type like:
from collections import namedtuple #: A resource entry returned from :py:meth:`RootResource.walk_resources`. #: #: Attribtues: #: name (unicode): ... #: list_href (unicode): ... #: resource (...): ... #: is_list (bool): ... ResourceEntry = namedtuple('ResourceEntry', ('name', 'list_href', 'resource', 'is_list')
then you can
Yields: ResourceEntry
and document theResourceEntry
as above. -
djblets/webapi/resources/root.py (Diff revision 12) Can we pull
self.walk_resources(child, child_href)
into a variable and iterate over that instead? -
-
-
-
-
djblets/webapi/resources/root.py (Diff revision 12) "Unregister"
This may not be a word, but what do dictionaries know? They let frobnicate be a word :)
-
-
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) """Unit tests for the ExtensionRootResourceMixin."""
No need for full class paths here.
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) setUp
must callsuper(ExtensionTemplateTests, self).setUp()
or you're going to end up with weird, unsolvable test failures sometimes :) -
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) Docstrings should be of the form:
"""Single line summary. Multi-line description. """
See my comment on the
ExtensionTemplateTests
for what is required here (i.e., not this much :)) -
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) setUp
must callsuper(RootResourceTemplateRegistrationTests, self).setUp()
or you're going to end up with weird, unsolvable test failures sometimes :) -
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 12) Pull this out to a top level element, otherwise we are creating a new class each test pass. If you want, you can do:
class RootResourceTemplateRegistrationTests(TestCase): """....""" class MockExtensionManager(object): pass def setUp(self): self.root_resource = RootResource() self.extension_manager = self.MockExtensionmanager() # ...
Additionally, this should inherit from
object
to be a new style class, which are more sensible.
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 13 (+286 -11) |
Change Summary:
Added final tests to test_extension_resource_mixin.py and fixed an error I'd introduced in a previous patchset.
Testing Done: |
|
||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Commit: |
|
||||||||||||||||||||||||||||||||||||
Diff: |
Revision 14 (+309 -11) |
-
-
-
-
djblets/extensions/resources.py (Diff revision 14) Missing
**kwargs (dict)
Also, what is
kwargs
used for here? -
djblets/extensions/resources.py (Diff revision 14) Since this isnt a
type
object, can we rename this toext
orextension
? -
djblets/extensions/resources.py (Diff revision 14) Since
walk_resources
returns the namedtuple instance and we're not using all the fields we can do:for entry in self.walk_resources(resource, partial_href): self.register_uri_template(entry.name, entry.href, ext_resource)
-
djblets/extensions/resources.py (Diff revision 14) Can we pull out
self.get_extension_resource()
into a variable at the top of the function and reuse it in each iteration? -
-
-
-
-
djblets/webapi/resources/root.py (Diff revision 14) Python standard libraries go in between
__future__
imports and 3rd party imports (likedjango
anddjblets
). -
-
djblets/webapi/resources/root.py (Diff revision 14) Can you reformat this as:
#: Attributes #: field (type): #: Description of field... #: #: field (type): #: Description of field...
It makes it a bit easier to scan
-
djblets/webapi/resources/root.py (Diff revision 14) This should actually be the full type, i.e.
djblets.webapi.responses.WebAPIResponseError
. -
-
djblets/webapi/resources/root.py (Diff revision 14) This should yield
self.ResourceEntry(resource.name_plural, list_href, resource, True)
. -
djblets/webapi/resources/root.py (Diff revision 14) This should yield
self.ResourceEntry(name, list_href, resource, is_list)
. -
-
-
-
djblets/webapi/resources/root.py (Diff revision 14) Can we name this
relative_resource
orparent_resource
? -
-
djblets/webapi/resources/root.py (Diff revision 14) Again, can we rename this
relative_resource
orparent_resource
? -
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) Can we call this
TestChildResourceOne
-
-
-
-
-
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) Docstrings should be of the form
"""Single line summary. Multi-line description. """
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) Rename to
expected_result
,actual_result
.Also, I think this would be better formatted as the following:
expected_result = { 'extension': 'http://testserver/{extension_name}/', 'extensions': 'http://testserver/extensions/', 'mock_resource_1s': ( 'http://testserver/extensions/djblets.webapi.tests.' 'test_extension_resource_mixin.MockExtension/mock-resource-1s/' ), 'mock_resource_2s': ( 'http://testserver/extensions/djblets.webapi.tests. 'test_extension_resource_mixin.MockExtension/mock-resource-2s/' ), }
-
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) Docstrings should be of the form
"""Single line summary. Multi-line description. """
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) You should be providing the extension resource to this, e.g.
self.ext_mgr = ExtensionManager('') self.ext_resource = ExtensionResource(self.ext_mgr) self.root_resource = RootResource([ext_resource])
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) Can we just call these
.ext_mgr
and.extension
? -
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) Reformat this as:
self.root_resource._registered_uri_templates = { None: {'extension-1': '/first/'}, self.mock_extension: { 'extensions': 'http://localhost:8080/api/extensions/', }, }
Also, isn't this backwards? Shouldn't this be:
{ self.mock_extension: {'extension-1': '/first/'}, None: {'extensions': 'http://localhost:8080/api/extensions'}, }
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) Rename as
actual_result
,expected_result
? -
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) Reformat this as:
self.root_resource._uri_templates = { 'key1': 'value', 'key2': 'value', }
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) Rename as
expected_result
,actual_result
? -
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) This should be formatted as:
self.assertFalse(self.root_resource._registered_uri_tempaltes[ self.mock_extension])
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) Reformat this as:
self.root_resource._uri_templates = { 'key1': 'value', 'key2': 'value', }
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) Reformat this as:
self.root_resource._uri_templates = { 'key1': 'value', 'key2': 'value', }
-
Tool: PEP8 Style Checker Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py Tool: Pyflakes Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py
-
-
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 13) Col: 80 E501 line too long (87 > 79 characters)
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 13) Col: 30 E126 continuation line over-indented for hanging indent
-
-
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) Col: 80 E501 line too long (81 > 79 characters)
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) Col: 80 E501 line too long (81 > 79 characters)
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 14) Col: 30 E126 continuation line over-indented for hanging indent
-
Tool: Pyflakes Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 13) 'SpyAgency' imported but unused
Description: |
|
|||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Testing Done: |
|
Description: |
|
---|
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 15 (+353 -10) |
-
Tool: Pyflakes Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 16 (+356 -10) |
-
Tool: Pyflakes Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py
-
-
-
djblets/extensions/resources.py (Diff revisions 14 - 16) Reformat as:
self.register_uri_template(entry.name, entry.list_href, ext_resource)
-
-
-
djblets/webapi/resources/root.py (Diff revisions 14 - 16) djblets.webapi.resources.base.WebAPIResource
-
djblets/webapi/resources/root.py (Diff revisions 14 - 16) "Whether or not the resource is a list resource."
-
djblets/webapi/resources/root.py (Diff revisions 14 - 16) Could you reformat this as:
templates[registered_name] = ( '%s%s' % (href, registered_href) )
-
djblets/webapi/resources/root.py (Diff revisions 14 - 16) Reformat as:
yield self.ResourceEntry(resource.name, object_href, resource, False)
-
djblets/webapi/resources/root.py (Diff revisions 14 - 16) This can be simplified to:
for entry in self.walk_resources(child, child_href): yield entry
-
djblets/webapi/resources/root.py (Diff revisions 14 - 16) Reformat as:
self._registered_uri_templates[relative_resource][name] = \ relative_path
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 17 (+353 -10) |
-
Tool: Pyflakes Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py
-
This should be the last review pass!
-
djblets/extensions/resources.py (Diff revision 17) Can you make a note that the subclass that uses this mixin must implement this?
-
djblets/webapi/resources/root.py (Diff revision 17) How about:
for name, href in six.iteritems(unassigned_templates): # ....
-
djblets/webapi/resources/root.py (Diff revision 17) for entry in self.walk_resources(self, base_href):
-
djblets/webapi/resources/root.py (Diff revision 17) How about:
if is_list: list_templates = self._registered_uri_templates.get( resource, {}) for name, href in six.iteritems(list_templates): templates[name] = ( '%s%s' % (entry.href, href) )
-
djblets/webapi/resources/root.py (Diff revision 17) This can be simplified to
for entry in self.walk_resources(child, child_href): yield entry
-
djblets/webapi/resources/root.py (Diff revision 17) for entry in self.walk_resources(child, child_href): yield entry
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 18 (+356 -10) |
-
Tool: Pyflakes Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py
-
-
djblets/extensions/resources.py (Diff revision 18) This doesn't really describe this properly.
I would say it's a mixin for root resources that make use of ExtensionResource.
You should then flesh out the description in the docstring to explain why this exists, what it accomplishes.
-
-
-
-
-
djblets/extensions/resources.py (Diff revision 18) This is missing a "Returns" block that states the return type and content.
-
-
-
-
djblets/webapi/resources/root.py (Diff revision 18) Indentation level for "Args" and "Yields" is wrong.
-
djblets/webapi/resources/root.py (Diff revision 18) ResourceEntry
needs to:1) Be on the next line
2) BeRootResource.ResourceEntry
(these need to be either absolute paths, if outside the current module, or relative to the current module).
3) Have a suitable description. -
djblets/webapi/resources/root.py (Diff revision 18) Let's construct all these with keyword arguments instead of positional arguments for the values.
-
-
-
-
djblets/webapi/resources/root.py (Diff revision 18) _registered_uri_templates
and_uri_templates
are implementation details. Docs should focus on a higher level saying what this does, not how it does it. -
-
djblets/webapi/resources/root.py (Diff revision 18) Needs to be an absolute class path.
Should also include
, optional
after the type. -
djblets/webapi/resources/root.py (Diff revision 18) You can simplify much of this and reduce dictionary accesses:
templates = self._registered_uri_templates.setdefault(relative_resource, {}) templates[name] = relative_path
-
djblets/webapi/resources/root.py (Diff revision 18) These are pretty conflicting statements. The second overrides the first.
-
-
djblets/webapi/resources/root.py (Diff revision 18) Same as above with the doc content. It should be higher level than what internal fields are being modified.
-
-
-
djblets/webapi/resources/root.py (Diff revision 18) Better to do:
try: del self._registered_uri_templates[relative_resource][name] except KeyError: pass
This does two things:
1) Doesn't fail (like the current code) if
relative_resource
isn't in the dictionary.
2) Saves a lookup (or two). We assume the lookups and deletion will work, and ignore if it doesn't, instead of checking up-front (often unnecessarily). -
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) Blank line between these. Djblets is the current project, and so has its own import group.
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) These can be one import statement.
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) Please use numbers instead of spelling them out for these classes.
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) Missing a trailing period.
Same with the ones below.
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) This isn't in the proper form. It should be:
""" ... Returns djblets.extensions.resources.ExtensionResource <description here> """
That said, these are unit tests. They're not necessary here unless they're test functions or utility functions designed to automate parts of the testing.
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) This should probably be
ExtensionRootResourceMixinTests
. -
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) This should be done first, probably.
Blank line between it and the setters.
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) So two things:
1) When testing a method, the docstring needs to list the class name and the proper name of the function (this is missing the
_
at the beginning).
2) We don't want to necessarily test just this function, but rather "is this done when an extension is initialized." So you should test from the starting point of the signal.With #2, you probably want this called:
Testing ExtensionRootResourceMixin generates URI templates when extensions initialized
These comments apply below as well.
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) This whole thing should be used inline below, like:
self.assertEqual( actual_result, { ... })
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) Should just use
assertEqual
, notassert*Equal
methods.Also, flip these. Thing you're testing should be first. Expected value second.
Same with all other tests.
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) This should also be inline below.
Same with other tests.
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) This should be
RootResourceTests
, and should live in its own file (test_root_resource.py
). -
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) Consistency is good. Both of these should look the same:
.... = { self.ext_resource: { 'extensions': ..., }, None: { 'extensions': ..., }, }
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) This can be one line.
Should ideally use keyword arguments, which would push to two lines, but they should start immediately after the
(
in the function call. -
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 18) These calls will read better if you use keyword arguments.
-
-
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 19 (+374 -10) |
-
Tool: Pyflakes Processed Files: djblets/webapi/tests/test_root_resource.py djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/webapi/tests/test_root_resource.py djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py
-
-
djblets/webapi/tests/test_extension_resource_mixin.py (Diff revision 19) Col: 9 E303 too many blank lines (2)
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 20 (+372 -10) |
-
Tool: Pyflakes Processed Files: djblets/webapi/tests/test_root_resource.py djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/webapi/tests/test_root_resource.py djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py
-
-
-
djblets/extensions/resources.py (Diff revision 20) This is not a class, it is an instance (isn't it?) Rename this to
ext
orextension
.If it is a class then you want to use
type
and mention it must be a subclass ofdjblets.extensions.Extension
. -
-
-
-
-
djblets/webapi/resources/root.py (Diff revision 20) Can you change this to be a
@classmethod
?e.g.
@classmethod def walk_resources(cls, resource, list_href):
and replace all usages of
self
withcls
? -
-
djblets/webapi/resources/root.py (Diff revision 20) Don't wrap this. You will get a error from review bot but you can drop it.
-
Summary: |
|
||||
---|---|---|---|---|---|
Commit: |
|
||||
Diff: |
Revision 21 (+377 -10) |
-
Tool: Pyflakes Processed Files: djblets/webapi/tests/test_root_resource.py djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/webapi/tests/test_root_resource.py djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py
-
-
-
-
-
djblets/extensions/resources.py (Diff revision 21) I actually don't think we normally document *args and **kwargs, since I often think that it's for passing through arguments as opposed to doing something with them. Like, in this case, __init__ is not doing anything with either *args or **kwargs. Same goes for the other documentation of *args and **kwargs in this file. If I'm contradicting feedback from another mentor, ignore me - but I've been looking around, and I just don't see documentation for these things in our tree, and I suspect that's on purpose.
-
djblets/webapi/resources/root.py (Diff revision 21) This is an interesting documentation style choice, the #:. Can you explain why you made that choice? I'm not familiar with that style.
-
Description: |
|
---|
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 22 (+375 -10) |
-
Tool: PEP8 Style Checker Processed Files: djblets/webapi/tests/test_root_resource.py djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py Tool: Pyflakes Processed Files: djblets/webapi/tests/test_root_resource.py djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py
-
-
-
Almost at the finish line! Everything here is either a tiny doc fix or a tiny syntax/consistency issue.
-
-
djblets/extensions/resources.py (Diff revision 22) This (and all other references to
djblets.extensions.Extension
) needs to bedjblets.extensions.extension.Extension
). The former doesn't exist, and only the latter will properly generate links in the docs. -
djblets/extensions/resources.py (Diff revision 22) Public methods must come before private method. This should be right after
__init__
. -
-
-
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 23 (+377 -10) |
-
Tool: Pyflakes Processed Files: djblets/webapi/tests/test_root_resource.py djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/webapi/tests/test_root_resource.py djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py
-
-
-
This looks great! I just have a couple minor things left, and then I think we're ready to land this :)
-
-
djblets/webapi/resources/root.py (Diff revision 23) Can you add a comment here just saying that we're clearing the cache so that future lookups will take into account the new template? Just helps make it clear what's going on there.
-
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 24 (+379 -10) |
-
Tool: Pyflakes Processed Files: djblets/webapi/tests/test_root_resource.py djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/webapi/tests/test_root_resource.py djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py
-
-
-
-
djblets/webapi/resources/root.py (Diff revision 24) Is there special meaning in having
#:
? It also seems somewhat inconsistent (eg. the line withlist_href
doesn't have it).
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 25 (+379 -10) |
-
Tool: Pyflakes Processed Files: djblets/webapi/tests/test_root_resource.py djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py Tool: PEP8 Style Checker Processed Files: djblets/webapi/tests/test_root_resource.py djblets/extensions/resources.py djblets/webapi/tests/test_extension_resource_mixin.py djblets/webapi/resources/root.py
-
-
-
-
djblets/webapi/resources/root.py (Diff revisions 23 - 25) Missing trailing period. All comments should be in full sentence format.
-
Change Summary:
Added missing trailing periods. Re-ran unit tests, all okay.
Branch: |
|
||||
---|---|---|---|---|---|
Commit: |
|
||||
Diff: |
Revision 26 (+379 -10) |
Checks run (1 failed, 1 succeeded)
flake8
Commit: |
|
||||
---|---|---|---|---|---|
Diff: |
Revision 27 (+381 -10) |