File: relative_path_ext.py

package info (click to toggle)
python-mkdocs 0.15.3-5
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 4,476 kB
  • ctags: 1,313
  • sloc: python: 3,840; makefile: 22; xml: 20
file content (147 lines) | stat: -rw-r--r-- 4,804 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
"""
# Relative Path Markdown Extension

During the MkDocs build we rewrite URLs that link to local
Markdown or media files. Using the following pages configuration
we can look at how the output is changed.

    pages:
    - ['index.md']
    - ['tutorial/install.md']
    - ['tutorial/intro.md']

## Markdown URLs

When linking from `install.md` to `intro.md` the link would
simply be `[intro](intro.md)`. However, when we build
`install.md` we place it in a directory to create nicer URLs.
This means that the path to `intro.md` becomes `../intro/`

## Media URLs

To make it easier to work with media files and store them all
under one directory we re-write those to all be based on the
root. So, with the following markdown to add an image.

    ![The initial MkDocs layout](img/initial-layout.png)

The output would depend on the location of the Markdown file it
was added too.

Source file         | Generated Path    | Image Path                   |
------------------- | ----------------- | ---------------------------- |
index.md            | /                 | ./img/initial-layout.png     |
tutorial/install.md | tutorial/install/ | ../img/initial-layout.png    |
tutorial/intro.md   | tutorial/intro/   | ../../img/initial-layout.png |

"""

from __future__ import unicode_literals

import logging
import os

from markdown.extensions import Extension
from markdown.treeprocessors import Treeprocessor
from markdown.util import AMP_SUBSTITUTE

from mkdocs import utils
from mkdocs.exceptions import MarkdownNotFound

log = logging.getLogger(__name__)


def _iter(node):
    # TODO: Remove when dropping Python 2.6. Replace this
    # function call with note.iter()
    return [node] + node.findall('.//*')


def path_to_url(url, nav, strict):

    scheme, netloc, path, params, query, fragment = (
        utils.urlparse(url))

    if scheme or netloc or not path or AMP_SUBSTITUTE in url:
        # Ignore URLs unless they are a relative link to a markdown file.
        # AMP_SUBSTITUTE is used internally by Markdown only for email,which is
        # not a relative link. As urlparse errors on them, skip explicitly
        return url

    if nav and not utils.is_markdown_file(path):
        path = utils.create_relative_media_url(nav, path)
    elif nav:
        # If the site navigation has been provided, then validate
        # the internal hyperlink, making sure the target actually exists.
        target_file = nav.file_context.make_absolute(path)

        if target_file.startswith(os.path.sep):
            target_file = target_file[1:]

        if target_file not in nav.source_files:
            source_file = nav.file_context.current_file
            msg = (
                'The page "%s" contained a hyperlink to "%s" which '
                'is not listed in the "pages" configuration.'
            ) % (source_file, target_file)

            # In strict mode raise an error at this point.
            if strict:
                raise MarkdownNotFound(msg)
            # Otherwise, when strict mode isn't enabled, log a warning
            # to the user and leave the URL as it is.
            log.warning(msg)
            return url
        path = utils.get_url_path(target_file, nav.use_directory_urls)
        path = nav.url_context.make_relative(path)
    else:
        path = utils.get_url_path(path).lstrip('/')

    # Convert the .md hyperlink to a relative hyperlink to the HTML page.
    fragments = (scheme, netloc, path, params, query, fragment)
    url = utils.urlunparse(fragments)
    return url


class RelativePathTreeprocessor(Treeprocessor):

    def __init__(self, site_navigation, strict):
        self.site_navigation = site_navigation
        self.strict = strict

    def run(self, root):
        """Update urls on anchors and images to make them relative

        Iterates through the full document tree looking for specific
        tags and then makes them relative based on the site navigation
        """

        for element in _iter(root):

            if element.tag == 'a':
                key = 'href'
            elif element.tag == 'img':
                key = 'src'
            else:
                continue

            url = element.get(key)
            new_url = path_to_url(url, self.site_navigation, self.strict)
            element.set(key, new_url)

        return root


class RelativePathExtension(Extension):
    """
    The Extension class is what we pass to markdown, it then
    registers the Treeprocessor.
    """

    def __init__(self, site_navigation, strict):
        self.site_navigation = site_navigation
        self.strict = strict

    def extendMarkdown(self, md, md_globals):
        relpath = RelativePathTreeprocessor(self.site_navigation, self.strict)
        md.treeprocessors.add("relpath", relpath, "_end")