diff --git a/force_bdss/io/workflow_reader.py b/force_bdss/io/workflow_reader.py
index 78b5a947fdf90e401d5e2613ea884fb48481cf31..adead5f8e13f6214622b20ece5169b02921660f5 100644
--- a/force_bdss/io/workflow_reader.py
+++ b/force_bdss/io/workflow_reader.py
@@ -10,22 +10,56 @@ SUPPORTED_FILE_VERSIONS = ["1"]
 
 
 class InvalidFileException(Exception):
-    pass
+    """Raised if the file is invalid for some reason"""
 
 
 class InvalidVersionException(InvalidFileException):
-    pass
+    """Raised if the version tag does not satisfy the currently
+    supported list."""
 
 
 class WorkflowReader(HasStrictTraits):
+    """
+    Reads the workflow from a file.
+    """
+    #: The bundle registry. The reader needs it to create the
+    #: bundle-specific model objects.
     bundle_registry = Instance(BundleRegistryPlugin)
 
     def __init__(self, bundle_registry, *args, **kwargs):
+        """Initializes the reader.
+
+        Parameters
+        ----------
+        bundle_registry: BundleRegistryPlugin
+            The bundle registry that provides lookup services
+            for a bundle identified by a given id.
+        """
         self.bundle_registry = bundle_registry
 
         super(WorkflowReader, self).__init__(*args, **kwargs)
 
     def read(self, file):
+        """Reads the file and returns a Workflow object.
+        If any problem is found, raises an InvalidFileException or a
+        derived, more specialized exception.
+
+        Parameters
+        ----------
+        file: File
+            A file object containing the data of the workflow in the
+            appropriate json format.
+
+        Returns
+        -------
+        Workflow
+            An instance of the model tree, rooted at Workflow.
+
+        Raises
+        ------
+        InvalidFileException
+            Raised if the file is corrupted or cannot be read by this reader.
+        """
         json_data = json.load(file)
 
         try:
@@ -57,10 +91,23 @@ class WorkflowReader(HasStrictTraits):
                                        "Unable to find key {}".format(e))
         return wf
 
-    def _extract_mco(self, json_data):
+    def _extract_mco(self, wf_data):
+        """Extracts the MCO from the workflow dictionary data.
+
+        Parameters
+        ----------
+        wf_data: dict
+            the content of the workflow key in the top level dictionary data.
+
+        Returns
+        -------
+        a BaseMCOModel instance of the bundle-specific MCO driver, or None
+        if no MCO is specified in the file (as in the case of premature
+        saving).
+        """
         registry = self.bundle_registry
 
-        mco_data = json_data.get("multi_criteria_optimizer")
+        mco_data = wf_data.get("multi_criteria_optimizer")
         if mco_data is None:
             # The file was saved without setting an MCO.
             # The file is valid, we simply can't run any optimization yet.
@@ -69,24 +116,49 @@ class WorkflowReader(HasStrictTraits):
         mco_id = mco_data["id"]
         mco_bundle = registry.mco_bundle_by_id(mco_id)
         return mco_bundle.create_model(
-            json_data["multi_criteria_optimizer"]["model_data"])
+            wf_data["multi_criteria_optimizer"]["model_data"])
+
+    def _extract_data_sources(self, wf_data):
+        """Extracts the data sources from the workflow dictionary data.
 
-    def _extract_data_sources(self, json_data):
+        Parameters
+        ----------
+        wf_data: dict
+            the content of the workflow key in the top level dictionary data.
+
+        Returns
+        -------
+        list of BaseDataSourceModel instances. Each BaseDataSourceModel is an
+        instance of the bundle specific model class. The list can be empty.
+        """
         registry = self.bundle_registry
 
         data_sources = []
-        for ds_entry in json_data["data_sources"]:
+        for ds_entry in wf_data["data_sources"]:
             ds_id = ds_entry["id"]
             ds_bundle = registry.data_source_bundle_by_id(ds_id)
             data_sources.append(ds_bundle.create_model(ds_entry["model_data"]))
 
         return data_sources
 
-    def _extract_kpi_calculators(self, json_data):
+    def _extract_kpi_calculators(self, wf_data):
+        """Extracts the KPI calculators from the workflow dictionary data.
+
+        Parameters
+        ----------
+        wf_data: dict
+            the content of the workflow key in the top level dictionary data.
+
+        Returns
+        -------
+        list of BaseKPICalculatorModel instances. Each BaseKPICalculatorModel
+        is an instance of the bundle specific model class. The list can be
+        empty.
+        """
         registry = self.bundle_registry
 
         kpi_calculators = []
-        for kpic_entry in json_data["kpi_calculators"]:
+        for kpic_entry in wf_data["kpi_calculators"]:
             kpic_id = kpic_entry["id"]
             kpic_bundle = registry.kpi_calculator_bundle_by_id(kpic_id)