Repository: oppia/oppia

Issue:
Create a ClassifierTrainingJob.to_player_dict() function
<!--
  - Thanks for taking the time to report a bug in the Oppia project.
  - Before filing a new issue, please do a quick search to check that it hasn't
  - already been filed on the [issue tracker](https://github.com/oppia/oppia/issues)._
  -->

**Improvement Suggestion**
This is not a bug, this is an improvement suggestion in existing code.
ExplorationStateClassifierMappingTests creates an "[expected_state_classifier_mapping](https://github.com/oppia/oppia/blob/c34a59aafc1c35a8ba39d731f92d0682c1d15390/core/controllers/reader_test.py#L213)" which in turn contains **text** with **algorithhm_id, classifier_data, data_schema_version**. Currently this is working fine. But from android application perspective we have to create a class containing those three keys. So as a improvement in backend code, can we create a **to_player_dict()** function in **[ClassifierTrainingJob](https://github.com/oppia/oppia/blob/78867995faa010e77f0a12453008bb05ce61fcd8/core/domain/classifier_domain.py#L28)** class in **classifier_domain.py** file. This function will return **algorithhm_id, classifier_data, data_schema_version** to ExplorationStateClassifierMappingTests or wherever else necessary.

Making these changes will make backend code and android code much more understandable to everyone because of class/function similarities.

Create a ClassifierTrainingJob.to_player_dict() function
<!--
  - Thanks for taking the time to report a bug in the Oppia project.
  - Before filing a new issue, please do a quick search to check that it hasn't
  - already been filed on the [issue tracker](https://github.com/oppia/oppia/issues)._
  -->

**Improvement Suggestion**
This is not a bug, this is an improvement suggestion in existing code.
ExplorationStateClassifierMappingTests creates an "[expected_state_classifier_mapping](https://github.com/oppia/oppia/blob/c34a59aafc1c35a8ba39d731f92d0682c1d15390/core/controllers/reader_test.py#L213)" which in turn contains **text** with **algorithhm_id, classifier_data, data_schema_version**. Currently this is working fine. But from android application perspective we have to create a class containing those three keys. So as a improvement in backend code, can we create a **to_player_dict()** function in **[ClassifierTrainingJob](https://github.com/oppia/oppia/blob/78867995faa010e77f0a12453008bb05ce61fcd8/core/domain/classifier_domain.py#L28)** class in **classifier_domain.py** file. This function will return **algorithhm_id, classifier_data, data_schema_version** to ExplorationStateClassifierMappingTests or wherever else necessary.

Making these changes will make backend code and android code much more understandable to everyone because of class/function similarities.



Discussion:
Hey, can I work on this improvement?
Hi @andrew-sharpl, sure, go ahead! 
@seanlip I would like to work on this
@DubeySandeep Is this issue still open? If yes, can you assign it to me?
@xlogix, Yeah, I've assigned you! :) 
Hey, can I work on this improvement?
Hi @andrew-sharpl, sure, go ahead! 
@seanlip I would like to work on this
@DubeySandeep Is this issue still open? If yes, can you assign it to me?
@xlogix, Yeah, I've assigned you! :) 

Resolving patch:
diff --git a/core/controllers/reader.py b/core/controllers/reader.py
--- a/core/controllers/reader.py
+++ b/core/controllers/reader.py
@@ -232,16 +232,8 @@ def get(self, exploration_id):
                 list(exploration.states.keys())))
         for index, state_name in enumerate(exploration.states.keys()):
             if classifier_training_jobs[index] is not None:
-                classifier_data = classifier_training_jobs[
-                    index].classifier_data
-                algorithm_id = classifier_training_jobs[index].algorithm_id
-                data_schema_version = (
-                    classifier_training_jobs[index].data_schema_version)
-                state_classifier_mapping[state_name] = {
-                    'algorithm_id': algorithm_id,
-                    'classifier_data': classifier_data,
-                    'data_schema_version': data_schema_version
-                }
+                state_classifier_mapping[state_name] = (
+                    classifier_training_jobs[index].to_player_dict())
 
         self.values.update({
             'can_edit': (
diff --git a/core/domain/classifier_domain.py b/core/domain/classifier_domain.py
--- a/core/domain/classifier_domain.py
+++ b/core/domain/classifier_domain.py
@@ -294,6 +294,21 @@ def to_dict(self):
             'data_schema_version': self._data_schema_version
         }
 
+    def to_player_dict(self):
+        """Constructs a dict containing a training job domain object's
+        algorithm_id, classifier_data and data_schema_version.
+
+        Returns:
+            A dict containing training job domain object's algorithm_id,
+            classifier_data and data_schema_version.
+        """
+
+        return {
+            'algorithm_id': self._algorithm_id,
+            'classifier_data': self._classifier_data,
+            'data_schema_version': self._data_schema_version
+        }
+
     def validate(self):
         """Validates the training job before it is saved to storage."""
 
diff --git a/core/domain/exp_services.py b/core/domain/exp_services.py
--- a/core/domain/exp_services.py
+++ b/core/domain/exp_services.py
@@ -1530,16 +1530,8 @@ def get_user_exploration_data(
             exploration_id, exploration.version, exploration.states))
     for index, state_name in enumerate(exploration.states):
         if classifier_training_jobs[index] is not None:
-            classifier_data = classifier_training_jobs[
-                index].classifier_data
-            algorithm_id = classifier_training_jobs[index].algorithm_id
-            data_schema_version = (
-                classifier_training_jobs[index].data_schema_version)
-            state_classifier_mapping[state_name] = {
-                'algorithm_id': algorithm_id,
-                'classifier_data': classifier_data,
-                'data_schema_version': data_schema_version
-            }
+            state_classifier_mapping[state_name] = (
+                classifier_training_jobs[index].to_player_dict())
 
     editor_dict = {
         'auto_tts_enabled': exploration.auto_tts_enabled,


Test patch:
diff --git a/core/domain/classifier_domain_test.py b/core/domain/classifier_domain_test.py
--- a/core/domain/classifier_domain_test.py
+++ b/core/domain/classifier_domain_test.py
@@ -110,6 +110,42 @@ def test_to_dict(self):
             expected_training_job_dict,
             observed_training_job.to_dict())
 
+    def test_to_player_dict(self):
+        expected_training_job_dict = {
+            'job_id': 'exp_id1.SOME_RANDOM_STRING',
+            'algorithm_id': 'TextClassifier',
+            'interaction_id': 'TextInput',
+            'exp_id': 'exp_id1',
+            'exp_version': 1,
+            'next_scheduled_check_time':
+                datetime.datetime.strptime(
+                    '2017-08-11 12:42:31', '%Y-%m-%d %H:%M:%S'),
+            'state_name': 'a state name',
+            'status': 'NEW',
+            'training_data': [
+                {
+                    'answer_group_index': 1,
+                    'answers': ['a1', 'a2']
+                },
+                {
+                    'answer_group_index': 2,
+                    'answers': ['a2', 'a3']
+                }
+            ],
+            'classifier_data': {},
+            'data_schema_version': 1
+        }
+        expected_training_job_player_dict = {
+            'algorithm_id': 'TextClassifier',
+            'classifier_data': {},
+            'data_schema_version': 1
+        }
+        observed_training_job = self._get_training_job_from_dict(
+            expected_training_job_dict)
+        self.assertDictEqual(
+            expected_training_job_player_dict,
+            observed_training_job.to_player_dict())
+
     def test_validation_exp_id(self):
         self.training_job_dict['exp_id'] = 1
         training_job = self._get_training_job_from_dict(self.training_job_dict)