Repository: deeppavlov/DeepPavlov

Issue:
Add __getitem__() method for Chainer class
`str` argument for getting by id and `int` for getting by index


Discussion:

Resolving patch:
diff --git a/deeppavlov/core/commands/infer.py b/deeppavlov/core/commands/infer.py
--- a/deeppavlov/core/commands/infer.py
+++ b/deeppavlov/core/commands/infer.py
@@ -60,6 +60,9 @@ def build_model(config: Union[str, Path, dict], mode: str = 'infer',
 
         component = from_params(component_config, mode=mode, serialized=component_serialized)
 
+        if 'id' in component_config:
+            model._components_dict[component_config['id']] = component
+
         if 'in' in component_config:
             c_in = component_config['in']
             c_out = component_config['out']
diff --git a/deeppavlov/core/common/chainer.py b/deeppavlov/core/common/chainer.py
--- a/deeppavlov/core/common/chainer.py
+++ b/deeppavlov/core/common/chainer.py
@@ -14,7 +14,7 @@
 
 import pickle
 from logging import getLogger
-from typing import Union, Tuple, List, Optional
+from typing import Union, Tuple, List, Optional, Hashable
 
 from deeppavlov.core.common.errors import ConfigError
 from deeppavlov.core.models.component import Component
@@ -61,10 +61,68 @@ def __init__(self, in_x: Union[str, list] = None, out_params: Union[str, list] =
         self.forward_map = set(self.in_x)
         self.train_map = self.forward_map.union(self.in_y)
 
+        self._components_dict = {}
+
         self.main = None
 
-    def append(self, component: Component, in_x: [str, list, dict]=None, out_params: [str, list]=None,
-               in_y: [str, list, dict]=None, main=False):
+    def __getitem__(self, item):
+        if isinstance(item, int):
+            in_params, out_params, component = self.train_pipe[item]
+            return component
+        return self._components_dict[item]
+
+    def _ipython_key_completions_(self):
+        return self._components_dict.keys()
+
+    def __repr__(self):
+        reversed_components_dict = {v: f'{repr(k)}: ' for k, v in self._components_dict.items()
+                                    if isinstance(v, Hashable)}
+
+        components_list = []
+        for in_params, out_params, component in self.train_pipe:
+            component_repr = repr(component)
+            if isinstance(component, Hashable) and component in reversed_components_dict:
+                component_repr = reversed_components_dict[component] + component_repr
+            else:
+                for k, v in self._components_dict.items():
+                    if v is component:
+                        component_repr = f'{k}: {component_repr}'
+                        break
+            components_list.append(component_repr)
+
+        return f'Chainer[{", ".join(components_list)}]'
+
+    def _repr_pretty_(self, p, cycle):
+        """method that defines ``Struct``'s pretty printing rules for iPython
+
+        Args:
+            p (IPython.lib.pretty.RepresentationPrinter): pretty printer object
+            cycle (bool): is ``True`` if pretty detected a cycle
+        """
+        if cycle:
+            p.text('Chainer(...)')
+        else:
+            with p.group(8, 'Chainer[', ']'):
+                reversed_components_dict = {v: k for k, v in self._components_dict.items()
+                                            if isinstance(v, Hashable)}
+                # p.pretty(self.__prepare_repr())
+                for i, (in_params, out_params, component) in enumerate(self.train_pipe):
+                    if i > 0:
+                        p.text(',')
+                        p.breakable()
+                    if isinstance(component, Hashable) and component in reversed_components_dict:
+                        p.pretty(reversed_components_dict[component])
+                        p.text(': ')
+                    else:
+                        for k, v in self._components_dict.items():
+                            if v is component:
+                                p.pretty(k)
+                                p.text(': ')
+                                break
+                    p.pretty(component)
+
+    def append(self, component: Component, in_x: [str, list, dict] = None, out_params: [str, list] = None,
+               in_y: [str, list, dict] = None, main: bool = False):
         if isinstance(in_x, str):
             in_x = [in_x]
         if isinstance(in_y, str):


Test patch: