Github user aviyoop commented on a diff in the pull request:
https://github.com/apache/incubator-ariatosca/pull/207#discussion_r151087783
--- 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'):
presentation._link_locators()
- # 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:
- # The imports inherit the parent presenter class and
use the current location as
- # their origin location
- import_location = UriLocation(import_location)
- executor.submit(self._present, import_location,
location, presenter_class,
- executor)
-
return presentation
- def _read(self, location, origin_location):
- if self.context.reading.reader is not None:
- return self.context.reading.reader.read()
- loader =
self.context.loading.loader_source.get_loader(self.context.loading, location,
-
origin_location)
- reader =
self.context.reading.reader_source.get_reader(self.context.reading, location,
- loader)
- return reader.read()
+
+class _Result(object):
--- End diff --
Should document the purpose of this class
---