Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improving the dev workflow: Milestone 1.1.3 Custom pylint checks #4967

Merged
merged 55 commits into from
May 25, 2018
Merged

Improving the dev workflow: Milestone 1.1.3 Custom pylint checks #4967

merged 55 commits into from
May 25, 2018

Conversation

apb7
Copy link
Contributor

@apb7 apb7 commented May 22, 2018

Explanation

This PR adds a custom checker for docstrings. The Google Style Docstring checker provided by Pylint has been modified according to the docstring style followed at Oppia.

Checks enabled:

  1. redundant-yields-doc
  2. missing-return-doc
  3. missing-return-type-doc
  4. missing-yield-doc
  5. missing-yield-type-doc
  6. missing-param-doc
  7. missing-type-doc
  8. differing-param-doc
  9. differing-type-doc

Checks disabled:

  1. multiple-constructor-doc
  2. missing-raises-doc
  3. redundant-returns-doc

Checklist

  • The PR title starts with "Fix #bugnum: ", followed by a short, clear summary of the changes.
  • The PR explanation includes the words "Fixes #bugnum: ...".
  • The linter/Karma presubmit checks have passed.
    • These should run automatically, but if not, you can manually trigger them locally using python scripts/pre_commit_linter.py and bash scripts/run_frontend_tests.sh.
  • The PR is made from a branch that's not called "develop".
  • The PR follows the style guide.
  • The PR is assigned to an appropriate reviewer.
    • If you're a new contributor, please ask on Gitter for someone to assign a reviewer.
    • If you're not sure who the appropriate reviewer is, please assign to the issue's "owner" -- see the "talk-to" label on the issue.

@apb7 apb7 self-assigned this May 22, 2018
@codecov-io
Copy link

codecov-io commented May 22, 2018

Codecov Report

Merging #4967 into develop will increase coverage by 0.27%.
The diff coverage is n/a.

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #4967      +/-   ##
===========================================
+ Coverage    44.56%   44.84%   +0.27%     
===========================================
  Files          387      389       +2     
  Lines        23345    23510     +165     
  Branches      3800     3830      +30     
===========================================
+ Hits         10403    10542     +139     
- Misses       12942    12968      +26
Impacted Files Coverage Δ
...ensions/objects/templates/NumberWithUnitsEditor.js 4.54% <0%> (ø)
...ead/domain/objects/NumberWithUnitsObjectFactory.js 96.5% <0%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ec10dc6...5769c5f. Read the comment docs.

Copy link
Member

@seanlip seanlip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @apb7, I answered your question, but also noticed a lot of issues. I haven't read the whole PR super carefully and haven't identified all instances of the issues, so please take a look at the rest of it as well and make changes as needed. Thanks.

/cc @kevinlee12

utils.py Outdated
@@ -631,6 +631,9 @@ def _get_short_language_description(full_language_description):

Args:
full_language_description: str. Short description of the language.

Returns:
full_language_description: str. Short description of the language.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Returns" shouldn't have a varname.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -211,6 +211,9 @@ def dispatch(self):
Raises:
Exception: The CSRF token is missing.
UnauthorizedUserException: The CSRF token is invalid.

Returns:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and elsewhere: don't need Returns if there's nothing to return.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seanlip: This checker mandates that if the function body has a return statement, it should be a part of the docstring even if it returns None. Therefore to enable the checker, I have added this. Also, I had discussed this with @kevinlee12 and have mentioned this in the PR explanation under the header Important Points. Thanks!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, sorry, I didn't read the PR explanation since I started looking only at the specific comment you linked me to. Thanks for the pointer.

I think the standard in our codebase is to exclude the return statement if nothing is returned. Otherwise it's just cruft. Can we do that?

Also can we include the special cases *args and **kwargs in the regex?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the former question, the checker works as follows:

  1. It checks the function definition, that is, the parameters, raises, returns and yields parts.
  2. If they ( parameters, raises, returns, and yields) are present, then it checks them in the corresponding function docstring.
    Therefore if we use return in the function body, we need to have a docstring part corresponding to it.
    For the latter part, we can try do so.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the first point: can the checker be modified to detect a return statement that is "return {{something}}" instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we possibly follow this convention? What do you suggest?
Thanks!

Copy link
Member

@seanlip seanlip May 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See if you can do some investigation per my previous comment: can we detect "return {{something}}" and trigger on that, rather than "return"? If so, great; if not, why not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, let me look into this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO

Copy link
Contributor Author

@apb7 apb7 May 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the problem is not with return. These statements do not require docstrings. This function actually has a return statement:

return self.handle_exception(e, self.app.debug)

The handle_exception function does not return anything other than None. Therefore this statement can be safely removed.

@@ -572,6 +575,9 @@ def is_csrf_token_valid(cls, user_id, token):
Args:
user_id: str. The user_id to validate the CSRF token against.
token: str. The CSRF token to validate.

Returns:
bool.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and elsewhere, an explanation of what is being returned is needed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done (here and elsewhere).

@@ -440,7 +443,7 @@ def handle_exception(self, exception, unused_debug_mode):
"""Overwrites the default exception handler.

Args:
exception: The exception that was thrown.
exception: exception. The exception that was thrown.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the class name (and therefore the type) is Exception

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -45,6 +45,10 @@ def test_can_play(self, exploration_id, **kwargs):

Args:
exploration_id: str. The exploration id.
kwargs: keyword_arguments.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and elsewhere: Keyword arguments.

(It's not a python variable, so you don't need to refer to it in snake case.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will require a modification of the regex since it allows only non-space characters for the argument type.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you're using keyword_arguments as a type. It's not a type. Use * instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -103,6 +103,9 @@ def reduce(key, stringified_values):
<exploration_id>:<exploration_version>:<state_name>
stringified_values: list(str). A list of stringified_values of the
submitted answers.

Yields:
Error.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't useful at all. When is it yielded? Under what circumstances? You will need to read and understand the method to find out.

Docstrings should always be written to help the person reading the code. If we start just writing them just for the sake of it then it's a bit pointless.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, for this case, where is the "Error" that's being yielded? As far as I can tell all the yields are just str.

So the docstring should just be:

    Yields:
        str. One of the following strings:
        - ...
        - ...

Please check the others too. It's really not a great idea to introduce docstrings that have the wrong types since that's only going to confuse devs. If you are unsure about types, ask me.

as exp_models.ExplorationModel.
activity_ids_list: A list of activity IDs (such as exploration IDS)
for which the latest commits will be retrieved.
activity_model_cls: storage_layer_object. The storage layer
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, the type is wrong. We have no type called "storage_layer_object".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be * since activity_model_cls can be one of exp_models.ExplorationModel of collection_models.CollectionModel?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be ExplorationModel|CollectionModel.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -375,7 +376,7 @@ def _handle_incoming_event(cls, active_realtime_layer, event_type, *args):
triggered and the total play count is incremented. If he/she
rates an exploration, an event of type `rate` is triggered and
average rating of the realtime model is refreshed.
*args:
args: arguments.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arguments is not a type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

'average_ratings': float. Average of average ratings across all
explorations.
Returns:
dict. with the following keys:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dict. This has the following keys: ...

(Use complete sentences please.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -0,0 +1,718 @@
# coding: utf-8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not keen on mixing up third-party code in our regular codebase like this.

Can we put this in third_party instead and refer to it somehow, swapping out methods (just for the duration of the linter run) if needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have third_party/ in .gitignore. Where should I put it then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have modified .gitignore to allow _check_docs_utils.py which has been placed in python-custom-checks. Thanks!

@apb7 apb7 assigned apb7 and unassigned kevinlee12 May 24, 2018
@@ -224,6 +224,9 @@ def _send_email(
the email.
reply_to_id: str or None. The unique reply-to id used in reply-to email
address sent to recipient.

Returns:
None.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, I just noticed that this function doesn't actually need to return the result of run_in_transaction() on line 269. I think we can drop the return (and modify other stuff accordingly), if it helps.

This might be applicable for some other functions too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So here can we remove all return statements from lines 244, 256 and 269?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That breaks the logic. So, no.

(Make sure you read the functions carefully and understand what they're doing. The fixes needed to bring the codebase into compliance with the linter are sweeping and should never be done cookie-cutter. There is a chance of breaking things here.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Let me look into the "None" issue.

Copy link
Contributor Author

@apb7 apb7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have checked and removed all return statements which were actually equivalent to None.

@apb7
Copy link
Contributor Author

apb7 commented May 24, 2018

Hi @seanlip! The backend tests are failing. The traceback:

======================================================================
FAIL: test_non_logged_in_users_cannot_create_threads_and_messages (core.controllers.feedback_test.FeedbackThreadPermissionsTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/apurv/dev/oppia/core/controllers/feedback_test.py", line 105, in test_non_logged_in_users_cannot_create_threads_and_messages
    }, self.csrf_token, expect_errors=True, expected_status_int=401)
  File "/home/apurv/dev/oppia/core/tests/test_utils.py", line 421, in post_json
    upload_files)
  File "/home/apurv/dev/oppia/core/tests/test_utils.py", line 432, in _send_post_request
    self.assertEqual(json_response.status_int, expected_status_int)
AssertionError: 302 != 401

---------------------------------------------------------------------
FAILED    core.controllers.feedback_test: 0 errors, 1 failures

@@ -244,7 +247,7 @@ def dispatch(self):
'%s: payload %s',
e, self.payload)

self.handle_exception(e, self.app.debug)
return self.handle_exception(e, self.app.debug)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found out the problem. This return is necessary. We cannot remove it although handle_exception returns None.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because execution continues going onward. An alternative is to do

self.handle_exception(e, self.app.debug)
return

Copy link
Member

@seanlip seanlip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @apb7, thanks! Made a couple comments; @kevinlee12 can you please take a closer look to verify correctness of docstrings and type information, and that no functional changes have been introduced in the core code?

Also, @apb7 -- is the only thing remaining to modify the checks so that they don't trigger on "return" without something actually being returned?

.gitignore Outdated
# The pre_commit_linter.py script uses _check_docs_utils.py placed
# in python-custom-checks directory under third_party directory.
# Therefore it is not ignored.
!third_party/python-custom-checks
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, no, this is not what I meant. I actually meant to locate the source file in third_party so that we do not have to ship it on github. Then modify the install scripts to download whatever is needed (pylint etc., or that specific file) and refer to it there.

That way, we don't ship/maintain code that is not ours (which is kind of the point of third-party in the first place).

Happy to chat about this if anything's not clear.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done as discussed. Thanks!

@@ -103,6 +103,9 @@ def reduce(key, stringified_values):
<exploration_id>:<exploration_version>:<state_name>
stringified_values: list(str). A list of stringified_values of the
submitted answers.

Yields:
Error.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, for this case, where is the "Error" that's being yielded? As far as I can tell all the yields are just str.

So the docstring should just be:

    Yields:
        str. One of the following strings:
        - ...
        - ...

Please check the others too. It's really not a great idea to introduce docstrings that have the wrong types since that's only going to confuse devs. If you are unsure about types, ask me.

@@ -244,7 +247,7 @@ def dispatch(self):
'%s: payload %s',
e, self.payload)

self.handle_exception(e, self.app.debug)
return self.handle_exception(e, self.app.debug)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because execution continues going onward. An alternative is to do

self.handle_exception(e, self.app.debug)
return

@apb7
Copy link
Contributor Author

apb7 commented May 25, 2018

@seanlip: All review comments have been addressed including the no "return" problem. Also, the backend tests were failing. I have tried to fix them too. Thanks!

Copy link
Member

@seanlip seanlip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @apb7, this looks like a much better approach IMO.

I've skimmed and made a few comments. I'm going to pass the rest of this review to @kevinlee12 (in terms of verifying varnames, types, descriptions, etc.).

@@ -0,0 +1,190 @@
# coding: utf-8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To double-check: all code in this file was originally written by us?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The initial helper functions are similar but modified. I have changed the docstrings as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused what you mean by "similar but modified", can you elaborate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pylint functions check for all Docstrings style. This has been modified to check only for our modified Google Docstrings style.

import os
import sys

import _check_docs_utils as utils
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to follow their convention here. We can just call our file docstrings_checker.py or similar and do import docstrings_checker.

In general try to avoid aliasing (import X as Y) where possible.

and filename.endswith('.py')]
# The file _check_docs_utils.py has to be excluded from this check
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But now this file is under our control, right? So we can do it according to our code style.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On removing this, I still get an error:

/home/apurv/dev/oppia/./scripts/docstrings_checker.py --> Line 171: Multiline docstring should end with a new line.
/home/apurv/dev/oppia/./scripts/docstrings_checker.py --> Line 183: Multiline docstring should end with a new line.

I looked into the working of _check_docstrings function and found out that it checks for """ at the start and end to identify multiline docstrings. Since the regex here also spans multiple lines, it produces the above error. Therefore we still require to disable this check for the file. Thanks!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we should not make a habit of disabling checks like this (in general). There are ways around this, e.g. you could write the multiline string a different way:

    [
        '...',
        '...'
    ].join('\n')

But, at worst, you would disable just the multiline docstring check for those two lines. It does not warrant disabling lint checks for the entire file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, used ''' instead if """. Done!

@@ -821,8 +821,14 @@ def _check_docstrings(all_files):
summary_messages = []
files_to_check = [
filename for filename in all_files if not
any(fnmatch.fnmatch(filename, pattern) for pattern in EXCLUDED_PATHS)
(any(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need the outer parens. Didn't this and the next line all fit in one line before?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -201,8 +201,8 @@ def test_manifest_syntax(dependency_type, dependency_dict):

Display warning message when there is an error and terminate the program.
Args:
dependency_type: dependency download format.
dependency_dict: manifest.json dependency dict.
dependency_type: dependency_download_format.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dependency_download_format is not a type. Could you please go through all your changes here and make sure that the types and descriptions are correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the type here be "*"?

Copy link
Member

@seanlip seanlip May 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know offhand. You'll need to read the code and investigate what the possible values for this argument are.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be str since test_manifest_syntax is called in validate_manifest. validate_manifest passes it download_format which is separated from dependencies. dependencies are separated from manifest_data, a JSON object.
@kevinlee12: Can you please see this once? Thanks!

Copy link
Contributor

@kevinlee12 kevinlee12 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @apb7, I left some more comments, ptal!

@@ -263,7 +263,7 @@ def _send_email_in_transaction():
recipient_id, recipient_email, sender_id, sender_name_email, intent,
email_subject, cleaned_html_body, datetime.datetime.utcnow())

return transaction_services.run_in_transaction(_send_email_in_transaction)
transaction_services.run_in_transaction(_send_email_in_transaction)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was the return removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kevinlee12: Please refer to this discussion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, thanks!

@@ -312,7 +312,7 @@ def _send_bulk_mail_in_transaction(instance_id=None):
instance_id, recipient_ids, sender_id, sender_name_email, intent,
email_subject, cleaned_html_body, datetime.datetime.utcnow())

return transaction_services.run_in_transaction(
transaction_services.run_in_transaction(
Copy link
Contributor

@kevinlee12 kevinlee12 May 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

@@ -931,6 +931,6 @@ def send_test_email_for_bulk_emails(tester_id, email_subject, email_body):
"""
tester_name = user_services.get_username(tester_id)
tester_email = user_services.get_email_from_user_id(tester_id)
return _send_email(
_send_email(
Copy link
Contributor

@kevinlee12 kevinlee12 May 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

Occurs when there is not exactly one interaction ID
for each exploration and version.
- Expected at least one item ID for exploration:
Occurs when there is not atleast one Item ID for
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at least (add space between the words)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -110,6 +110,9 @@ def __init__(
user last edited an exploration.
profile_picture_data_url: str or None. User uploaded profile
picture as a dataURI string.
default_dashboard: str|None. The dashboard the user wants.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rephrase to: The default dashboard of the user.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -110,6 +110,9 @@ def __init__(
user last edited an exploration.
profile_picture_data_url: str or None. User uploaded profile
picture as a dataURI string.
default_dashboard: str|None. The dashboard the user wants.
creator_dashboard_display_pref: str. The creator dashboard
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The creator dashboard of the user.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -92,7 +92,8 @@ def send_bulk_mail(
Args:
sender_email: str. The email address of the sender. This should be in
the form 'SENDER_NAME <SENDER_EMAIL_ADDRESS>'.
recipient_email: str. The email address of the recipient.
recipient_emails: list(str). The list of email addresses
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List of recipients' email addresses.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -290,6 +290,9 @@ def create_multi(cls, job_exploration_mappings):
Args:
job_exploration_mappings: list(TrainingJobExplorationMapping). The
list of TrainingJobExplorationMapping Domain objects.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Since Github won't let me comment there)

Please remove the space between new and TrainingJobExplorationMappingModel.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -0,0 +1,190 @@
# coding: utf-8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused what you mean by "similar but modified", can you elaborate?

@apb7
Copy link
Contributor Author

apb7 commented May 25, 2018

@kevinlee12: I have addressed all the review comments. Can you please take another look?
Thanks!

Copy link
Contributor

@kevinlee12 kevinlee12 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @apb7, some more nits, ptal!

@@ -143,6 +149,405 @@ def process_module(self, node):
'no-break-after-hanging-indent', line=line_num + 1)


# This class has been derived from
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modify to The following class was derived from

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -143,6 +149,405 @@ def process_module(self, node):
'no-break-after-hanging-indent', line=line_num + 1)


# This class has been derived from
# https://github.com/PyCQA/pylint/blob/master/pylint/extensions/docparams.py#L26.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the link, change it to the following one:
https://github.com/PyCQA/pylint/blob/377cc42f9e3116ff97cddd4567d53e9a3e24ebf9/pylint/extensions/docparams.py#L26

This is so that we chain this to a particular version that we are using.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@apb7
Copy link
Contributor Author

apb7 commented May 25, 2018

@kevinlee12: ptal! Thanks.

@apb7 apb7 assigned kevinlee12 and unassigned apb7 May 25, 2018
Copy link
Contributor

@kevinlee12 kevinlee12 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, thanks @apb7!

@@ -1583,6 +1587,8 @@ def get_next_page_of_all_non_private_commits(
urlsafe_start_cursor: str. If this is not None, then the returned
commits start from cursor location. Otherwise they start from the
beginning of the list of commits.
max_age: datetime.timedelta. The maximum age to which all non private
commits are fetch from the ExplorationCommitLogEntry.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...are fetched...

@kevinlee12 kevinlee12 dismissed seanlip’s stale review May 25, 2018 16:35

Dismissing since I'm taking over final review.

@kevinlee12 kevinlee12 merged commit b00ad88 into oppia:develop May 25, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants