Esempio n. 1
0
    def testType(self):
        prop = base.Property('foo', 42, int)
        self.assertEqual(prop.name, 'foo')
        self.assertEqual(prop.default, 42)
        self.assertEqual(prop.type, int)
        self.assertEqual(prop.required, False)

        with self.assertRaises(exceptions.MooseDocsException) as e:
            base.Property('foo', ptype='int')
        gold = "The supplied property type (ptype) must be of type 'type', but 'str' provided."
        self.assertEqual(e.exception.message, gold)
Esempio n. 2
0
class PageNodeBase(base.NodeBase, mixins.TranslatorObject):
    """
    Base class for content tree.

    TODO: combine with LocationNodeBase, I don't remember why the two classes.
    """

    PROPERTIES = [base.Property('source', ptype=str)]
    COLOR = None

    def __init__(self, *args, **kwargs):
        mixins.TranslatorObject.__init__(self)
        base.NodeBase.__init__(self, *args, **kwargs)

    def build(self):
        """Performs a 'build', this is called by Translator."""
        self.write()

    def write(self):
        """Write the file to the destination, see LocationNodeBase."""
        pass
Esempio n. 3
0
class LocationNodeBase(PageNodeBase):
    """
    Base class for locations (Directories and Files).
    """
    PROPERTIES = [base.Property('base', ptype=str, default='')]

    def __init__(self, *args, **kwargs):
        PageNodeBase.__init__(self, *args, **kwargs)
        self.extension = None

        _, self.extension = os.path.splitext(self.source)
        self.name = os.path.basename(self.source)

        self.fullpath = os.path.join(self.parent.fullpath,
                                     self.name) if self.parent else self.name

        CACHE[self.fullpath] = set([self])

    @property
    def local(self):
        """Returns the local directory/filename."""
        return self.fullpath

    @property
    def destination(self):
        """Returns the translator destination location."""
        return os.path.join(self.base, self.local)

    def write(self):
        """
        Creates directories that do not exist within the destination. This handles locking with
        multithreading package to avoid race condition on directory creation.
        """
        with self.translator.lock:
            dirname = os.path.dirname(self.destination)
            if dirname and not os.path.isdir(dirname):
                os.makedirs(dirname)

    def findall(self,
                name,
                maxcount=1,
                mincount=1,
                exc=exceptions.MooseDocsException):  #pylint: disable=no-self-use
        """
        Find method for locating pages.

        Inputs:
            name[str]: The name of the page to search.
            maxcount[int]: The maximum number of items to find (default: 1).
            mincount[int]: The minimum number of items to find (default: 1).
            exc[Exception]: The type of exception to raise if min/max are not satisfied.
        """

        if MooseDocs.LOG_LEVEL == logging.DEBUG:
            common.check_type('name', name, (str, unicode))
            common.check_type('mincount', mincount, (int))
            common.check_type('maxcount', maxcount, (int))
            common.check_type('exc', exc, (type, types.LambdaType, type(None)))

        try:
            return list(CACHE[name])

        except KeyError:
            pass

        nodes = set()
        for key in CACHE:
            if key.endswith(name):
                nodes.update(CACHE[key])

        if (maxcount is not None) and exc and (len(nodes) > maxcount):
            msg = "The 'maxcount' was set to {} but {} nodes were found for the name '{}'." \
                  .format(maxcount, len(nodes), name)
            for node in nodes:
                msg += '\n  {} (source: {})'.format(node.local, node.source)
            raise exc(msg)

        elif (mincount is not None) and exc and (len(nodes) < mincount):
            msg = "The 'mincount' was set to {} but {} nodes were found for the name '{}'." \
                  .format(mincount, len(nodes), name)
            for node in nodes:
                msg += '\n  {} (source: {})'.format(node.local, node.source)
            raise exc(msg)

        CACHE[name] = nodes
        return list(nodes)

    def relativeSource(self, other):
        """ Location of this page related to the other page."""
        return os.path.relpath(self.local, os.path.dirname(other.local))

    def relativeDestination(self, other):
        """
        Location of this page related to the other page.

        Inputs:
            other[LocationNodeBase]: The page that this page is relative too.
        """
        return os.path.relpath(self.destination,
                               os.path.dirname(other.destination))

    def console(self):
        """Define the anytree screen output."""
        return '{} ({}): {}, {}'.format(self.name, self.__class__.__name__,
                                        self.local, self.source)
Esempio n. 4
0
class MarkdownNode(FileNode):
    """
    Node for content to be converted via Translator.

    This object handles cache of the content so when the Translator calls multiple builds it doesn't
    rebuild all the content.

    #TODO: Test the re-build cache.
    #TODO: Re-name this to TranslateNode and get the extensions from Reader/Renderer objects.
    """

    PROPERTIES = [base.Property('content', ptype=unicode)]

    def __init__(self, *args, **kwargs):
        FileNode.__init__(self, *args, **kwargs)

        self._modified = 0
        if self.source and os.path.exists(self.source):
            self._modified = os.path.getmtime(self.source)

        self._ast = None
        self._result = None
        self._index = None

    @property
    def destination(self):
        """The content destination (override)."""
        return super(MarkdownNode, self).destination.replace('.md', '.html')

    @property
    def ast(self):
        """Return the current AST."""
        return self._ast

    @property
    def result(self):
        """Return the rendered result."""
        return self._result

    @property
    def index(self):
        """Return the index."""
        return self._index

    def tokenize(self):
        """
        Perform tokenization of content, using cache if the content has not changed.
        """
        if self.modified() or (self.content is None):
            self._ast = None
            self._result = None
            self.read()

        if self._ast is None:
            self._ast = tokens.Token(None)
            self.translator.reader.parse(self._ast, self.content)

        return self._ast

    def render(self, ast):
        """
        Render supplied tokens to the output format.
        """
        if self._result is None:
            self._result = self.translator.renderer.render(ast)
        return self._result

    def read(self):
        """
        Read the content for conversion.
        """
        if self.source and os.path.exists(self.source):
            LOG.debug('READ %s', self.source)
            self._modified = os.path.getmtime(self.source)
            self.content = common.read(self.source)  #pylint: disable=attribute-defined-outside-init

    def modified(self):
        """
        Returns True if the content has been modified from the last call.
        """
        if self.source and os.path.exists(self.source):
            return os.path.getmtime(self.source) > self._modified
        return True

    def write(self):
        """
        Write the converted text to the output destination.
        """
        if self._result is not None:
            LOG.debug('WRITE %s -> %s', self.source, self.destination)
            LocationNodeBase.write(self)  # Creates directories
            with codecs.open(self.destination, 'w', encoding='utf-8') as fid:
                fid.write(self._result.write())

    def buildIndex(self, home):
        """
        Build the search index.
        """
        if (self._index is None) and (self._result is not None):
            self._index = []
            for section in anytree.search.findall_by_attr(
                    self._result, 'section'):
                name = self.name
                if name.endswith('.md'):
                    name = name[:-3]
                text = section['data-section-text']
                location = urlparse.urlsplit(self.destination.replace(self.base, home)) \
                    ._replace(scheme=None, netloc=None, fragment=str(section['id'])).geturl()
                self._index.append(
                    dict(name=name, text=text, location=location))

    def build(self):
        """
        Build method for livereload.
        """
        self.translator.current = self
        self.translator.reinit()
        ast = self.tokenize()
        self.render(ast)
        self.write()
        self.translator.current = None
Esempio n. 5
0
 def testRequired(self):
     prop = base.Property('foo', 42, int, True)
     self.assertEqual(prop.name, 'foo')
     self.assertEqual(prop.default, 42)
     self.assertEqual(prop.type, int)
     self.assertEqual(prop.required, True)
Esempio n. 6
0
 class TestNode(base.NodeBase):
     PROPERTIES = [base.Property('root')]
Esempio n. 7
0
 def testDefault(self):
     prop = base.Property('foo', 42)
     self.assertEqual(prop.name, 'foo')
     self.assertEqual(prop.default, 42)
     self.assertEqual(prop.type, None)
     self.assertEqual(prop.required, False)
Esempio n. 8
0
 class Time(base.NodeBase):
     PROPERTIES = [base.Property('hour', required=True)]
Esempio n. 9
0
 class Node(base.NodeBase):
     PROPERTIES = [base.Property('class_')]
Esempio n. 10
0
 class Time(base.NodeBase):
     PROPERTIES = [base.Property('hour', default=24)]
Esempio n. 11
0
 class Time(base.NodeBase):
     PROPERTIES = [
         base.Property('hour', ptype=int),
         base.Property('minute')
     ]
Esempio n. 12
0
 class Date(base.NodeBase):
     PROPERTIES = [
         base.Property('month'),
         base.Property('year', 1980),
         base.Property('day', 24, int)
     ]
Esempio n. 13
0
 def testConstructException(self):
     with self.assertRaises(exceptions.MooseDocsException) as e:
         base.Property('foo', 42, str)
     self.assertIn("must be of type 'str'", e.exception.message)
Esempio n. 14
0
 def testKeyword(self):
     prop = base.Property('foo', required=True, default=42, ptype=int)
     self.assertEqual(prop.name, 'foo')
     self.assertEqual(prop.default, 42)
     self.assertEqual(prop.type, int)
     self.assertEqual(prop.required, True)