2 new revisions:

Revision: 39a8a60bac73
Author:   Mikko Korpela <[email protected]>
Date:     Thu Dec  1 04:32:24 2011
Log:      Remove JsDataModelWriter
http://code.google.com/p/robotframework/source/detail?r=39a8a60bac73

Revision: 20e5edef7799
Author:   Mikko Korpela <[email protected]>
Date:     Thu Dec  1 04:32:37 2011
Log:      Automated merge with https://code.google.com/p/robotframework/
http://code.google.com/p/robotframework/source/detail?r=20e5edef7799

==============================================================================
Revision: 39a8a60bac73
Author:   Mikko Korpela <[email protected]>
Date:     Thu Dec  1 04:32:24 2011
Log:      Remove JsDataModelWriter
http://code.google.com/p/robotframework/source/detail?r=39a8a60bac73

Modified:
 /src/robot/conf/settings.py
 /src/robot/reporting/builders.py
 /src/robot/reporting/jsondatamodel.py
 /src/robot/reporting/resultwriter.py
 /src/robot/result/datamodel.py
 /src/robot/result/jsondatamodelhandlers.py
 /utest/reporting/test_jsondatamodel.py
 /utest/reporting/test_reporting.py
 /utest/result/test_jsoning.py

=======================================
--- /src/robot/conf/settings.py Wed Nov 30 05:53:07 2011
+++ /src/robot/conf/settings.py Thu Dec  1 04:32:24 2011
@@ -335,3 +335,25 @@
                 self['TagStatExclude'], self['TagStatCombine'],
                 self['TagDoc'], self['TagStatLink'])

+    def log_configuration(self):
+        return {
+            'title': self['LogTitle'],
+            'reportURL': self._url_from_path(self.log, self.report),
+            'splitLogBase': os.path.basename(os.path.splitext(self.log)[0])
+        }
+
+    def report_configuration(self):
+        return {
+            'title': self['ReportTitle'],
+            'logURL': self._url_from_path(self.report, self.log),
+            'background' : self._resolve_background_colors(),
+        }
+
+    def _url_from_path(self, source, destination):
+        if not destination:
+            return None
+        return utils.get_link_path(destination, os.path.dirname(source))
+
+    def _resolve_background_colors(self):
+        colors = self['ReportBackground']
+ return {'pass': colors[0], 'nonCriticalFail': colors[1], 'fail': colors[2]}
=======================================
--- /src/robot/reporting/builders.py    Thu Dec  1 01:36:44 2011
+++ /src/robot/reporting/builders.py    Thu Dec  1 04:32:24 2011
@@ -20,6 +20,7 @@

 from robot.errors import DataError
 from robot.output import LOGGER
+from robot.reporting.jsondatamodel import ScriptBlockWriter
 from robot.result.serializer import RebotXMLWriter
 from robot.version import get_full_version
 from robot import utils
@@ -70,18 +71,18 @@

 class _HTMLFileBuilder(_Builder):

-    def _write_file(self, path, template):
+    def _write_file(self, path, config, template):
         with codecs.open(path, 'w', encoding='UTF-8') as outfile:
-            writer = HTMLFileWriter(outfile, self._model)
+            writer = HTMLFileWriter(outfile, self._model, config)
             for line in _WebContentFile(template):
                 writer.line(line)


 class LogBuilder(_HTMLFileBuilder):

-    def build(self, path):
+    def build(self, path, config):
         try:
-            self._write_file(path, 'log.html')
+            self._write_file(path, config, 'log.html')
             self._write_split_logs_if_needed(path)
         except EnvironmentError, err:
LOGGER.error("Writing log file '%s' failed: %s" % (err.filename, err.strerror))
@@ -90,7 +91,7 @@

     def _write_split_logs_if_needed(self, path):
         base = os.path.splitext(path)[0]
- for index, (keywords, strings) in enumerate(self._model._split_results): + for index, (keywords, strings) in enumerate(self._model.split_results):
             index += 1  # enumerate accepts start index only in Py 2.6+
self._write_split_log(index, keywords, strings, '%s-%d.js' % (base, index))

@@ -104,9 +105,9 @@

 class ReportBuilder(_HTMLFileBuilder):

-    def build(self, path):
+    def build(self, path, config):
         try:
-            self._write_file(path, 'report.html')
+            self._write_file(path, config, 'report.html')
         except EnvironmentError, err:
LOGGER.error("Writing report file '%s' failed: %s" % (path, err.strerror))
         else:
@@ -119,9 +120,10 @@
     _css_media_matcher = re.compile('media=\"([^\"]+)\"')

     #TODO: output js_model_writer
-    def __init__(self, outfile, output):
+    def __init__(self, outfile, model, config):
         self._outfile = outfile
-        self._output = output
+        self._model = model
+        self._config = config

     def line(self, line):
         if self._is_output_js(line):
@@ -155,7 +157,7 @@
     def _write_output_js(self):
         separator = '</script>\n<script type="text/javascript">\n'
         self._write_tag('script', 'type="text/javascript"',
- lambda: self._output.write_to(self._outfile, separator)) + lambda: ScriptBlockWriter(separator).write_to(self._outfile, self._model, self._config))

     def _inline_js_file(self, line):
         self._write_tag('script', 'type="text/javascript"',
=======================================
--- /src/robot/reporting/jsondatamodel.py       Thu Dec  1 01:36:44 2011
+++ /src/robot/reporting/jsondatamodel.py       Thu Dec  1 04:32:24 2011
@@ -12,91 +12,7 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.

-import time
-
-from robot import utils
 from robot.reporting.jsondump import JsonDumper
-from robot.reporting.parsingcontext import TextIndex
-
-
-# TODO: This class (and module) has too much responsibilities
-
-class DataModelWriter(object):
-    _SUITE_KEY = 'suite'
-    _STRINGS_KEY = 'strings'
-
-    def __init__(self, robot_data, split_results=None):
-        self._robot_data = robot_data
-        self._split_results = split_results
-        self._settings = None
-        self._set_generated(time.localtime())
-
-    def _set_generated(self, timetuple):
-        genMillis = long(time.mktime(timetuple) * 1000) -\
-                        self._robot_data['baseMillis']
-        self._set_attr('generatedMillis', genMillis)
-        self._set_attr('generatedTimestamp',
-                       utils.format_time(timetuple, gmtsep=' '))
-
-    def _set_attr(self, name, value):
-        self._robot_data[name] = value
-
-    def set_settings(self, settings):
-        self._settings = settings
-
-    def write_to(self, output, separator='', split_threshold=9500):
- ScriptBlockWriter(separator, split_threshold).write_to(output, self)
-
-    def remove_keywords(self):
-        self._remove_keywords_from_suite(self._robot_data[self._SUITE_KEY])
-        self._prune_unused_indices()
-
-    # TODO: this and remove_keywords should be removed
-    # instead there should be a reportify or write_for_report_to method
-    def remove_errors(self):
-        self._robot_data.pop('errors')
-
-    def _remove_keywords_from_suite(self, suite):
-        suite[8] = []
-        for subsuite in suite[6]:
-            self._remove_keywords_from_suite(subsuite)
-        for test in suite[7]:
-            test[-1] = []
-
-    def _prune_unused_indices(self):
- used = self._collect_used_indices(self._robot_data[self._SUITE_KEY], set())
-        remap = {}
-        self._robot_data[self._STRINGS_KEY] = \
- list(self._prune(self._robot_data[self._STRINGS_KEY], used, remap))
-        self._remap_indices(self._robot_data[self._SUITE_KEY], remap)
-
- def _prune(self, data, used, index_remap, map_index=None, offset_increment=1):
-        offset = 0
-        for index, text in enumerate(data):
-            index = map_index(index) if map_index else index
-            if index in used:
-                index_remap[index] = index - offset
-                yield text
-            else:
-                offset += offset_increment
-
-    def _remap_indices(self, data, remap):
-        for i, item in enumerate(data):
-            if isinstance(item, TextIndex):
-                data[i] = remap[item]
-            elif isinstance(item, list):
-                self._remap_indices(item, remap)
-
-    def _collect_used_indices(self, data, result):
-        for item in data:
-            if isinstance(item, TextIndex):
-                result.add(item)
-            elif isinstance(item, list):
-                self._collect_used_indices(item, result)
-            elif isinstance(item, dict):
-                self._collect_used_indices(item.values(), result)
-                self._collect_used_indices(item.keys(), result)
-        return result


 class ScriptBlockWriter(object):
@@ -105,44 +21,41 @@
     _SUITE_KEY = 'suite'
     _STRINGS_KEY = 'strings'

-    def __init__(self, separator, split_threshold):
+    def __init__(self, separator, split_threshold=9500):
         self._separator = separator
         self._split_threshold = split_threshold

-    def write_to(self, output, model):
+    def write_to(self, output, model, config):
         writer = SeparatingWriter(output, self._separator)
         writer.write(self._OUTPUT+' = {};\n')
         writer.separator()
-        for key, value in model._robot_data.items():
-            self._write_output_element(model, key, value, writer)
+        self._write_suite(writer, model.suite)
+        writer.separator()
+        self._write_strings(model.strings, writer)
+        writer.separator()
+        for key, value in model.data.items():
+            writer.dump_json(self._output_var(key)+' = ', value)
             writer.separator()
-        writer.dump_json(self._SETTINGS+' = ', model._settings)
-
-    def _write_output_element(self, model ,key, value, writer):
-        if key == self._SUITE_KEY:
- splitWriter = SplittingSuiteWriter(writer, self._split_threshold) - data, mapping = splitWriter.write(model._robot_data[self._SUITE_KEY]) - writer.dump_json(self._str_out(self._SUITE_KEY)+' = ', data, mapping=mapping)
-        elif key == self._STRINGS_KEY:
-            self._dump_and_split_strings(model, writer)
-        else:
-            writer.dump_json(self._str_out(key)+' = ', value)
-
-    def _str_out(self, key):
+        writer.dump_json(self._SETTINGS+' = ', config)
+
+    def _write_suite(self, writer, suite):
+        splitWriter = SplittingSuiteWriter(writer, self._split_threshold)
+        data, mapping = splitWriter.write(suite)
+ writer.dump_json(self._output_var(self._SUITE_KEY)+' = ', data, mapping=mapping)
+
+    def _output_var(self, key):
         return self._OUTPUT+'["%s"]' % key

-    def _dump_and_split_strings(self, model, writer):
-        strings = model._robot_data[self._STRINGS_KEY]
-        writer.write(self._OUTPUT+'["'+self._STRINGS_KEY+'"] = [];\n')
+    def _write_strings(self, strings, writer):
+        writer.write(self._output_var(self._STRINGS_KEY)+' = [];\n')
         while strings:
             writer.separator()
-            writer.dump_json(self._str_out(self._STRINGS_KEY)
-                             +' = '+self._str_out(self._STRINGS_KEY)
+            writer.dump_json(self._output_var(self._STRINGS_KEY)
+                             +' = '+self._output_var(self._STRINGS_KEY)
+'.concat(', strings[:self._split_threshold], ');\n')
             strings = strings[self._split_threshold:]


-
 class SeparatingWriter(object):

     def __init__(self, output, separator=''):
=======================================
--- /src/robot/reporting/resultwriter.py        Wed Nov 30 06:12:07 2011
+++ /src/robot/reporting/resultwriter.py        Thu Dec  1 04:32:24 2011
@@ -12,16 +12,13 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.

-import os

 from robot.errors import DATA_ERROR
 from robot.result.builders import ResultFromXML
from robot.result.combiningvisitor import CombiningVisitor, KeywordRemovingVisitor
 from robot.result.datamodel import JSModelCreator
-from robot import utils

from .builders import LogBuilder, ReportBuilder, XUnitBuilder, OutputBuilder
-from .jsondatamodel import DataModelWriter


 class ResultWriter(object):
@@ -37,9 +34,11 @@
         if settings.xunit:
             XUnitBuilder(result.model).build(settings.xunit)
         if settings.log:
-            LogBuilder(result.log_model).build(settings.log)
+            LogBuilder(result.js_model).build(settings.log,
+                                              settings.log_configuration())
         if settings.report:
-            ReportBuilder(result.report_model).build(settings.report)
+            ReportBuilder(result.report_model).build(settings.report,
+ settings.report_configuration())
         return result.return_code


@@ -71,34 +70,15 @@
             creator = JSModelCreator(log_path=self._settings.log,
                                      split_log=self._settings.split_log)
self.model.visit(CombiningVisitor(creator, KeywordRemovingVisitor())) - self._js_model = DataModelWriter(creator.datamodel, creator.split_results)
+            self._js_model = creator.datamodel
         return self._js_model

     @property
     def log_model(self):
-        self.js_model.set_settings({
-            'title': self._settings['LogTitle'],
- 'reportURL': self._url_from_path(self._settings.log, self._settings.report), - 'splitLogBase': os.path.basename(os.path.splitext(self._settings.log)[0])
-        })
         return self.js_model

     @property
     def report_model(self):
-        self.js_model.set_settings({
-            'title': self._settings['ReportTitle'],
- 'logURL': self._url_from_path(self._settings.report, self._settings.log),
-            'background' : self._resolve_background_colors(),
-        })
         self.js_model.remove_errors()
         self.js_model.remove_keywords()
         return self.js_model
-
-    def _url_from_path(self, source, destination):
-        if not destination:
-            return None
-        return utils.get_link_path(destination, os.path.dirname(source))
-
-    def _resolve_background_colors(self):
-        colors = self._settings['ReportBackground']
- return {'pass': colors[0], 'nonCriticalFail': colors[1], 'fail': colors[2]}
=======================================
--- /src/robot/result/datamodel.py      Wed Nov 30 04:48:02 2011
+++ /src/robot/result/datamodel.py      Thu Dec  1 04:32:24 2011
@@ -30,10 +30,6 @@
             self._datamodel = self._build()
         return self._datamodel

-    @property
-    def split_results(self):
-        return self._context.split_results
-
     @property
     def _top(self):
         return self._handlers[-1]
=======================================
--- /src/robot/result/jsondatamodelhandlers.py  Wed Nov 30 04:48:02 2011
+++ /src/robot/result/jsondatamodelhandlers.py  Thu Dec  1 04:32:24 2011
@@ -11,9 +11,11 @@
 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
+import time

 from robot import utils
 from robot.output import LEVELS
+from robot.reporting.parsingcontext import TextIndex


 class _Handler(object):
@@ -89,11 +91,81 @@
 class ExecutionResultHandler(_Handler):

     def build(self, _):
-        return {'suite': self._suites[0],
+        return JsExecutionResult(
+            suite=self._suites[0],
+            strings=self._context.dump_texts(),
+            data= {
                 'stats': self._statistics,
                 'errors': self._errors,
-                'baseMillis': self._context.basemillis,
-                'strings': self._context.dump_texts()}
+                'baseMillis': self._context.basemillis
+            },
+            split_results= self._context.split_results
+        )
+
+
+class JsExecutionResult(object):
+
+    def __init__(self, suite, strings, data, split_results=None):
+        self.suite = suite
+        self.strings = strings
+        self.data = data
+        self._set_generated(time.localtime())
+        self.split_results = split_results or []
+
+    def _set_generated(self, timetuple):
+ genMillis = long(time.mktime(timetuple) * 1000) - self.data['baseMillis']
+        self.data['generatedMillis'] = genMillis
+ self.data['generatedTimestamp'] = utils.format_time(timetuple, gmtsep=' ')
+
+    def remove_keywords(self):
+        self._remove_keywords_from_suite(self.suite)
+        self._prune_unused_indices()
+
+    def remove_errors(self):
+        self.data.pop('errors')
+
+    def _remove_keywords_from_suite(self, suite):
+        suite[8] = []
+        for subsuite in suite[6]:
+            self._remove_keywords_from_suite(subsuite)
+        for test in suite[7]:
+            test[-1] = []
+
+    def _prune_unused_indices(self):
+        used = self._collect_used_indices(self.suite, set())
+        remap = {}
+        self.strings = \
+            list(self._prune(self.strings, used, remap))
+        self._remap_indices(self.suite, remap)
+
+ def _prune(self, data, used, index_remap, map_index=None, offset_increment=1):
+        offset = 0
+        for index, text in enumerate(data):
+            index = map_index(index) if map_index else index
+            if index in used:
+                index_remap[index] = index - offset
+                yield text
+            else:
+                offset += offset_increment
+
+    def _remap_indices(self, data, remap):
+        for i, item in enumerate(data):
+            if isinstance(item, TextIndex):
+                data[i] = remap[item]
+            elif isinstance(item, list):
+                self._remap_indices(item, remap)
+
+    def _collect_used_indices(self, data, result):
+        for item in data:
+            if isinstance(item, TextIndex):
+                result.add(item)
+            elif isinstance(item, list):
+                self._collect_used_indices(item, result)
+            elif isinstance(item, dict):
+                self._collect_used_indices(item.values(), result)
+                self._collect_used_indices(item.keys(), result)
+        return result
+


 class ErrorsHandler(_Handler):
=======================================
--- /utest/reporting/test_jsondatamodel.py      Mon Oct 24 03:12:31 2011
+++ /utest/reporting/test_jsondatamodel.py      Thu Dec  1 04:32:24 2011
@@ -1,7 +1,8 @@
 from StringIO import StringIO
 import unittest
+from robot.result.jsondatamodelhandlers import JsExecutionResult
 from robot.utils.asserts import assert_equals, assert_true
-from robot.reporting.jsondatamodel import DataModelWriter
+from robot.reporting.jsondatamodel import ScriptBlockWriter

 class TestDataModelWrite(unittest.TestCase):

@@ -11,9 +12,11 @@
         assert_true(lines[1].startswith('window.output["'), lines[1])
         assert_true(lines[-1].startswith('window.settings ='), lines[-1])

-    def _get_lines(self, data=None, separator=None, split_threshold=None):
+ def _get_lines(self, suite=None, strings=None, data=None, separator=None,
+                   split_threshold=None):
         output = StringIO()
- DataModelWriter(data or {'baseMillis':100}).write_to(output, separator=separator, split_threshold=split_threshold) + data = JsExecutionResult(suite, strings, data or {'baseMillis':100}) + ScriptBlockWriter(separator=separator, split_threshold=split_threshold).write_to(output, data, {})
         return output.getvalue().splitlines()

     def test_writing_datamodel_with_separator(self):
@@ -30,14 +33,16 @@

     def test_writing_datamodel_with_split_threshold_in_suite(self):
         suite = [1, [2, 3], [4, [5], [6, 7]], 8]
-        lines = self._get_lines(data={'baseMillis':100, 'suite':suite},
+        lines = self._get_lines(suite=suite,
+                                data={'baseMillis':100},
                                 split_threshold=2, separator='foo\n')
         parts = filter(lambda l: l.startswith('window.sPart'), lines)
assert_equals(parts, ['window.sPart0 = [2,3];', 'window.sPart1 = [6,7];', 'window.sPart2 = [4,[5],window.sPart1];', 'window.sPart3 = [1,window.sPart0,window.sPart2,8];'])
         self._assert_separators_in(lines, 'foo')

     def test_splitting_output_strings(self):
- lines = self._get_lines(data={'baseMillis':100, 'strings':['data' for _ in range(100)]},
+        lines = self._get_lines(strings=['data' for _ in range(100)],
+                                data={'baseMillis':100},
                                 split_threshold=9, separator='?\n')
parts = [l for l in lines if l.startswith('window.output["strings')]
         assert_equals(len(parts), 13)
=======================================
--- /utest/reporting/test_reporting.py  Wed Nov 30 07:38:25 2011
+++ /utest/reporting/test_reporting.py  Thu Dec  1 04:32:24 2011
@@ -13,14 +13,14 @@

 def set_write_log_mock():
     results = {'log_path': None}
-    def write_log(self, path, template):
+    def write_log(self, path, *args):
         results['log_path'] = path
     LogBuilder._write_file = write_log
     return results

 def set_write_report_mock():
     results = {'report_path': None}
-    def write_report(self, path, template):
+    def write_report(self, path, *args):
         results['report_path'] = path
     ReportBuilder._write_file = write_report
     return results
=======================================
--- /utest/result/test_jsoning.py       Wed Nov 30 15:22:40 2011
+++ /utest/result/test_jsoning.py       Thu Dec  1 04:32:24 2011
@@ -262,13 +262,13 @@
         self._visitor = JSModelCreator()
         self._context = self._visitor._context
         result.visit(self._visitor)
-        self._verify_message(self.datamodel['errors'][0],
+        self._verify_message(self.datamodel.data['errors'][0],
                              result.errors.messages[0])
- assert_equals(self._context.dump_texts()[self.datamodel['errors'][0][3]], '*s1-s1-t1-k1')
-        self._verify_suite(self.datamodel['suite'], result.suite)
- assert_equals(self.datamodel['baseMillis'], self._context.basemillis)
-        assert_equals(len(self.datamodel['strings']), 10)
-        assert_equals(self.datamodel['stats'],
+ assert_equals(self._context.dump_texts()[self.datamodel.data['errors'][0][3]], '*s1-s1-t1-k1')
+        self._verify_suite(self.datamodel.suite, result.suite)
+ assert_equals(self.datamodel.data['baseMillis'], self._context.basemillis)
+        assert_equals(len(self.datamodel.strings), 10)
+        assert_equals(self.datamodel.data['stats'],
             [[{'fail': 1, 'label': 'Critical Tests', 'pass': 0},
               {'fail': 1, 'label': 'All Tests', 'pass': 0}],
              [{'pass': 0, 'fail': 1, 'label': 'tagi'}],

==============================================================================
Revision: 20e5edef7799
Author:   Mikko Korpela <[email protected]>
Date:     Thu Dec  1 04:32:37 2011
Log:      Automated merge with https://code.google.com/p/robotframework/
http://code.google.com/p/robotframework/source/detail?r=20e5edef7799

Modified:
 /src/robot/result/jsondatamodelhandlers.py

=======================================
--- /src/robot/result/jsondatamodelhandlers.py  Thu Dec  1 03:39:28 2011
+++ /src/robot/result/jsondatamodelhandlers.py  Thu Dec  1 04:32:37 2011
@@ -11,9 +11,11 @@
 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
+import time

 from robot import utils
 from robot.output import LEVELS
+from robot.reporting.parsingcontext import TextIndex


 class _Handler(object):
@@ -89,11 +91,81 @@
 class ExecutionResultHandler(_Handler):

     def build(self, _):
-        return {'suite': self._suites[0],
+        return JsExecutionResult(
+            suite=self._suites[0],
+            strings=self._context.dump_texts(),
+            data= {
                 'stats': self._statistics,
                 'errors': self._errors,
-                'baseMillis': self._context.basemillis,
-                'strings': self._context.dump_texts()}
+                'baseMillis': self._context.basemillis
+            },
+            split_results= self._context.split_results
+        )
+
+
+class JsExecutionResult(object):
+
+    def __init__(self, suite, strings, data, split_results=None):
+        self.suite = suite
+        self.strings = strings
+        self.data = data
+        self._set_generated(time.localtime())
+        self.split_results = split_results or []
+
+    def _set_generated(self, timetuple):
+ genMillis = long(time.mktime(timetuple) * 1000) - self.data['baseMillis']
+        self.data['generatedMillis'] = genMillis
+ self.data['generatedTimestamp'] = utils.format_time(timetuple, gmtsep=' ')
+
+    def remove_keywords(self):
+        self._remove_keywords_from_suite(self.suite)
+        self._prune_unused_indices()
+
+    def remove_errors(self):
+        self.data.pop('errors')
+
+    def _remove_keywords_from_suite(self, suite):
+        suite[8] = []
+        for subsuite in suite[6]:
+            self._remove_keywords_from_suite(subsuite)
+        for test in suite[7]:
+            test[-1] = []
+
+    def _prune_unused_indices(self):
+        used = self._collect_used_indices(self.suite, set())
+        remap = {}
+        self.strings = \
+            list(self._prune(self.strings, used, remap))
+        self._remap_indices(self.suite, remap)
+
+ def _prune(self, data, used, index_remap, map_index=None, offset_increment=1):
+        offset = 0
+        for index, text in enumerate(data):
+            index = map_index(index) if map_index else index
+            if index in used:
+                index_remap[index] = index - offset
+                yield text
+            else:
+                offset += offset_increment
+
+    def _remap_indices(self, data, remap):
+        for i, item in enumerate(data):
+            if isinstance(item, TextIndex):
+                data[i] = remap[item]
+            elif isinstance(item, list):
+                self._remap_indices(item, remap)
+
+    def _collect_used_indices(self, data, result):
+        for item in data:
+            if isinstance(item, TextIndex):
+                result.add(item)
+            elif isinstance(item, list):
+                self._collect_used_indices(item, result)
+            elif isinstance(item, dict):
+                self._collect_used_indices(item.values(), result)
+                self._collect_used_indices(item.keys(), result)
+        return result
+


 class ErrorsHandler(_Handler):

Reply via email to