Github user tliron commented on a diff in the pull request:
https://github.com/apache/incubator-ariatosca/pull/207#discussion_r153008552
--- 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 --
I don't want to force parser writers to inherit from PresentationBase. They
are free to create their own classes as long as they support these methods.
Throughout the parser code you'll see these kinds of "hasattr" tests to see if
the classes have these features.
---