Repository: oppia/oppia

Issue:
Update docstrings in the Python backend code to follow the style guide.
We've been a bit lax about adding docstrings to code in the backend. Instead, we should be following the style guide: https://google.github.io/styleguide/pyguide.html?showone=Comments#Comments -- docstrings should define args, return values, exceptions, etc. The aim of this issue is to ensure that the backend code is properly documented; we will tackle this on a file-by-file basis.

Note: if you're a new contributor, this issue is a particularly good introductory one to tackle, since it will require reading, understanding and documenting the purpose of a file in the codebase, and help you get acquainted with how the Oppia backend is structured. It's important that you're able to communicate and write clearly, though!

Some useful tips:
-  Please follow our [style guide](https://github.com/oppia/oppia/wiki/Coding-style-guide#general) (and also the [Google Python style guide](https://google.github.io/styleguide/pyguide.html?showone=Comments#Comments)) when writing docstrings. Make sure to follow the patterns established there as closely as possible, including spacing, capitalization and punctuation. Also, it's a good idea to look at some of the existing files (see below) to get a sense of the correct format -- we recommend following this closely in order to maintain uniformity across the codebase.
- If applicable, make sure that the docstrings for all functions correctly specify the args, return values, etc. If a function has no args, you can omit the Args section; if it has no return value, you can omit the Returns section.
- If a docstring is not present in the code, or the existing one is too vague for you to understand what's going on just by looking at it, then it should be rewritten to be more clear. You'll often need to read the code as well, and do a grep on the callsites to see how it's being used, in order to get a clear understanding of what it's doing. This is good practice for learning how to navigate the codebase, and is an intended part of this project.
- If you feel that parts of the codebase are unclear or incorrectly factored, please feel free to bring this up! The whole point of docstrings is to improve code health and accessibility for new developers, so if you spot other things that can be done in service of that aim, we should also look into doing that.

**Completed:**
- [x] core.controllers.base @shaz13 
- [x] core.controllers.cron @saeedjassani
- [x] core.controllers.reader @96mohitm
- [x] core.domain.activity_domain @andromfins
- [x] core.domain.activity_services @souravsingh
- [x] core.domain.classifier_services @andromfins 
- [x] core.domain.collection_domain @domevit
- [x] core.domain.collection_services @kahkhang 
- [x] core.domain.config_services @vibhor98 
- [x] core.domain.email_manager @Oishikatta 
- [x] core.domain.exp_domain @domevit
- [x] core.domain.exp_services @DubeySandeep
- [x] core.domain.feedback_domain @terrameijar 
- [x] core.domain.feedback_jobs_continuous
- [x] core.domain.feedback_services @andimeo
- [x] core.domain.fs_domain @kartik-25 
- [x] core.domain.html_cleaner @seanlip
- [x] core.domain.param_domain @rohan-gulati
- [x] core.domain.rating_services @BojOnTheBeat 
- [x] core.domain.rights_manager @ayejay
- [x] core.domain.stats_domain @Arunabh98
- [x] core.domain.stats_jobs_continuous @Arunabh98 
- [x] core.domain.stats_jobs_one_off @zpuller
- [x] core.domain.stats_services @manoj-makkuboy 
- [x] core.domain.subscription_services @vibhor98 
- [x] core.domain.summary_services @domevit 
- [x] core.domain.user_jobs_continuous @shubha1593 
- [x] core.domain.user_services @Nalinc 
- [x] core.domain.value_generators_domain @meetsha 
- [x] core.jobs @brianrodri
- [x] core.platform.app_identity.gae_app_identity_services @ubhisat
- [x] core.platform.models @pranavsid98 
- [x] core.platform.transactions.gae_transaction_services @ubhisat
- [x] core.storage.base_model.gae_models @vojtechjelinek
- [x] core.storage.collection.gae_models @kaggis
- [x] core.storage.email.gae_models @rajan-garg
- [x] core.storage.exploration.gae_models @kirankonduru
- [x] core.storage.feedback.gae_models @naveenshukla
- [x] core.storage.file.gae_models @Ian91 
- [x] core.storage.job.gae_models @sasacocic
- [x] core.storage.statistics.gae_models @abhishekarya286
- [x] core.storage.user.gae_models @Anthony-Alridge 
- [x] core.tests.test_util_jobs @seanlip
- [x] core.tests.test_utils @vibhor98
- [x] utils @yashLadha 


Discussion:
@seanlip I would like to work in the issue.

Hi @souravsingh, do you think you could finish up #2051 first, please? Thanks! 

@seanlip I would like to work on this issue.

Hi @andromfins -- now that you've had a go at writing docstrings for a single class, would you mind picking one or two other files and doing the same thing for those? Let me know which ones you pick, so that I can mark you off against them.

Thanks!

Hi, i'm working on **core.domain.classifier_services**.

OK, thanks @andromfins! 

@seanlip Can I take a stab at other file to add docstrings?

Yep, sounds good. Could you take core.domain.html_cleaner? Thanks!

@andromfins -- are you still working on this?

  @seanlip Yes!

I would like to work on `core.domain.stats_domain`

@Arunabh98 assigned you on `core.domain.stats_domain`

Almost completed `core.domain.stats_domain`. Now working on `core.domain.stats_jobs_continuous`

hi @seanlip 
I am working on this issue.
I am writing the docstrings for /core/storage/collection/gae_models.py as i was assigned as a starting project.

@seanlip can I work on core.controllers.cron?
Yep, sounds good! I've updated the list.
@seanlip I'd like to work on core.storage.job.gae_models.
Sounds good, thanks @sasacocic! I've updated the list. 
@seanlip I'd like to work on core.platform.models. Thanks


Resolving patch:
diff --git a/core/platform/models.py b/core/platform/models.py
--- a/core/platform/models.py
+++ b/core/platform/models.py
@@ -33,9 +33,21 @@ def import_models(cls):
 
 
 class _Gae(_Platform):
+    """Provides platform-specific imports related to GAE (Google App Engine).
+    """
     @classmethod
     def import_models(cls, model_names):
+        """Imports and returns the storage modules listed in model_names.
 
+        Args:
+            model_names: list(str). List of storage module names.
+
+        Returns:
+            tuple(module): Tuple of storage modules.
+
+        Raises:
+            Exception: Invalid model name.
+        """
         returned_models = []
         for name in model_names:
             if name == NAMES.activity:
@@ -84,21 +96,46 @@ def import_models(cls, model_names):
 
     @classmethod
     def import_transaction_services(cls):
+        """Imports and returns gae_transaction_services module.
+
+        Returns:
+            module. The gae_transaction_services module.
+        """
         from core.platform.transactions import gae_transaction_services
         return gae_transaction_services
 
     @classmethod
     def import_current_user_services(cls):
+        """Imports and returns gae_current_user_services module.
+
+        Returns:
+            module. The gae_current_user_services module.
+        """
         from core.platform.users import gae_current_user_services
         return gae_current_user_services
 
     @classmethod
     def import_app_identity_services(cls):
+        """Imports and returns gae_app_identity_services module.
+
+        Returns:
+            module. The gae_app_identity_services module.
+        """
         from core.platform.app_identity import gae_app_identity_services
         return gae_app_identity_services
 
     @classmethod
     def import_email_services(cls):
+        """Imports and returns the email services module specified in feconf.py.
+
+        Returns:
+            module. The email_services module to use, based on the feconf.py
+            setting.
+
+        Raises:
+            Exception: feconf.EMAIL_SERVICE_PROVIDER does not correspond
+            to a valid email_services module.
+        """
         if feconf.EMAIL_SERVICE_PROVIDER == feconf.EMAIL_SERVICE_PROVIDER_GAE:
             from core.platform.email import gae_email_services
             return gae_email_services
@@ -113,16 +150,31 @@ def import_email_services(cls):
 
     @classmethod
     def import_memcache_services(cls):
+        """Imports and returns gae_memcache_services.
+
+        Returns:
+            module. The gae_memcache_services module.
+        """
         from core.platform.memcache import gae_memcache_services
         return gae_memcache_services
 
     @classmethod
     def import_taskqueue_services(cls):
+        """Imports and returns gae_taskqueue_services module.
+
+        Returns:
+            module. The gae_taskqueue_services module.
+        """
         from core.platform.taskqueue import gae_taskqueue_services
         return gae_taskqueue_services
 
     @classmethod
     def import_search_services(cls):
+        """Imports and returns gae_search_services module.
+
+        Returns:
+            module. The gae_search_services module.
+        """
         from core.platform.search import gae_search_services
         return gae_search_services
 
@@ -130,42 +182,95 @@ def import_search_services(cls):
 
 
 class Registry(object):
+    """Platform-agnostic interface for retrieving platform-specific modules.
+    """
+
+    # Maps platform names to the corresponding module registry classes.
     _PLATFORM_MAPPING = {
         _Gae.NAME: _Gae,
     }
 
     @classmethod
     def _get(cls):
+        """Returns the appropriate interface class for platform-specific
+        imports.
+
+        Returns:
+            class: The corresponding platform-specific interface class.
+        """
         return cls._PLATFORM_MAPPING.get(feconf.PLATFORM)
 
     @classmethod
     def import_models(cls, model_names):
+        """Imports and returns the storage modules listed in model_names.
+
+        Args:
+            model_names: list(str). List of storage module names.
+
+        Returns:
+            list(module). The corresponding storage-layer modules.
+        """
         return cls._get().import_models(model_names)
 
     @classmethod
     def import_current_user_services(cls):
+        """Imports and returns current_user_services module.
+
+        Returns:
+            module. The current_user_services module.
+        """
         return cls._get().import_current_user_services()
 
     @classmethod
     def import_transaction_services(cls):
+        """Imports and returns transaction_services module.
+
+        Returns:
+            module. The transaction_services module.
+        """
         return cls._get().import_transaction_services()
 
     @classmethod
     def import_app_identity_services(cls):
+        """Imports and returns app_identity_services module.
+
+        Returns:
+            module. The app_identity_services module.
+        """
         return cls._get().import_app_identity_services()
 
     @classmethod
     def import_email_services(cls):
+        """Imports and returns email_services module.
+
+        Returns:
+            module. The email_services module.
+        """
         return cls._get().import_email_services()
 
     @classmethod
     def import_memcache_services(cls):
+        """Imports and returns memcache_services module.
+
+        Returns:
+            module. The memcache_services module.
+        """
         return cls._get().import_memcache_services()
 
     @classmethod
     def import_taskqueue_services(cls):
+        """Imports and returns taskqueue_services module.
+
+        Returns:
+            module. The taskqueue_services module.
+        """
         return cls._get().import_taskqueue_services()
 
     @classmethod
     def import_search_services(cls):
+        """Imports and returns search_services module.
+
+        Returns:
+            module. The search_services module.
+        """
         return cls._get().import_search_services()


Test patch: