Github user mxmrlv commented on a diff in the pull request: https://github.com/apache/incubator-ariatosca/pull/207#discussion_r150782911 --- Diff: aria/parser/consumption/presentation.py --- @@ -86,52 +73,193 @@ def dump(self): self.context.presentation.presenter._dump(self.context) def _handle_exception(self, e): - if isinstance(e, AlreadyReadException): + if isinstance(e, _Skip): return super(Read, self)._handle_exception(e) - def _present(self, location, origin_location, presenter_class, executor): + def _present_all(self): + location = self.context.presentation.location + + if location is None: + self.context.validation.report('Read consumer: missing location') + return + + executor = self.context.presentation.create_executor() + try: + # This call may recursively submit tasks to the executor if there are imports + main = self._present(location, None, None, executor) + + # Wait for all tasks to complete + executor.drain() + + # Handle exceptions + for e in executor.exceptions: + self._handle_exception(e) + + results = executor.returns or [] + finally: + executor.close() + + results.insert(0, main) + + return main, results + + def _present(self, location, origin_canonical_location, origin_presenter_class, executor): # Link the context to this thread self.context.set_thread_local() - raw = self._read(location, origin_location) + # Canonicalize the location + if self.context.reading.reader is None: + loader, canonical_location = self._create_loader(location, origin_canonical_location) + else: + # If a reader is specified in the context then we skip loading + loader = None + canonical_location = location + + # Skip self imports + if canonical_location == origin_canonical_location: + raise _Skip() + + if self.context.presentation.cache: + # Is the presentation in the global cache? + try: + presentation = PRESENTATION_CACHE[canonical_location] + return _Result(presentation, canonical_location, origin_canonical_location) + except KeyError: + pass + + try: + # Is the presentation in the local cache? + presentation = self._cache[canonical_location] + return _Result(presentation, canonical_location, origin_canonical_location) + except KeyError: + pass + + # Create and cache new presentation + presentation = self._create_presentation(canonical_location, loader, origin_presenter_class) + self._cache[canonical_location] = presentation + # Submit imports to executor + if hasattr(presentation, '_get_import_locations'): + import_locations = presentation._get_import_locations(self.context) + if import_locations: + for import_location in import_locations: + import_location = UriLocation(import_location) + executor.submit(self._present, import_location, canonical_location, + presentation.__class__, executor) + + return _Result(presentation, canonical_location, origin_canonical_location) + + def _create_loader(self, location, origin_canonical_location): + loader = self.context.loading.loader_source.get_loader(self.context.loading, location, + origin_canonical_location) + + canonical_location = None + + if origin_canonical_location is not None: + cache_key = (origin_canonical_location, location) + try: + canonical_location = CANONICAL_LOCATION_CACHE[cache_key] + return loader, canonical_location + except KeyError: + pass + else: + cache_key = None + + canonical_location = loader.get_canonical_location() + + # Because retrieving the canonical location can be costly, we will try to cache it + if cache_key is not None: + CANONICAL_LOCATION_CACHE[cache_key] = canonical_location + + return loader, canonical_location + + def _create_presentation(self, canonical_location, loader, default_presenter_class): + # The reader we specified in the context will override + reader = self.context.reading.reader + + if reader is None: + # Read raw data from loader + reader = self.context.reading.reader_source.get_reader(self.context.reading, + canonical_location, loader) + + raw = reader.read() + + # Wrap raw data in presenter class if self.context.presentation.presenter_class is not None: - # The presenter class we specified in the context overrides everything + # The presenter class we specified in the context will override presenter_class = self.context.presentation.presenter_class else: try: presenter_class = self.context.presentation.presenter_source.get_presenter(raw) except PresenterNotFoundError: - if presenter_class is None: + if default_presenter_class is None: raise - # We'll use the presenter class we were given (from the presenter that imported us) - if presenter_class is None: - raise PresenterNotFoundError('presenter not found') + else: + presenter_class = default_presenter_class + + if presenter_class is None: + raise PresenterNotFoundError(u'presenter not found: {0}'.format(canonical_location)) presentation = presenter_class(raw=raw) - if presentation is not None and hasattr(presentation, '_link_locators'): + if hasattr(presentation, '_link_locators'): --- End diff -- maybe add default implementation for `_link_locators` and skip the if
---