File: pweb.py

package info (click to toggle)
python-pweave 0.30.3-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 5,064 kB
  • sloc: python: 30,281; makefile: 167
file content (211 lines) | stat: -rw-r--r-- 7,123 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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
import sys
import os
import re
import copy
import io

from .readers import PwebReaders
from . formatters import PwebFormats
from . processors import PwebProcessors
from jupyter_client import kernelspec

from .mimetypes import MimeTypes
from urllib import parse


class Pweb(object):
    """
    Process a Pweave document

    :param source: ``string`` name of the input document.
    :param doctype: ``string`` output format.
    :param informat: ``string`` input format
    :param kernel: ``string`` name of jupyter kernel used to run code
    :param output: ``string`` output path
    :param figdir: ``string`` figure directory
    :param mimetype: Source document's text mimetype. This is used to set cell
                     type in Jupyter notebooks
    """

    def __init__(self, source, doctype = None, *, informat = None, kernel = "python3",
                 output = None, figdir = 'figures', mimetype = None):
        self.source = source
        name, ext = os.path.splitext(os.path.basename(source))
        self.basename = name
        self.file_ext = ext
        self.figdir = figdir
        self.doctype = doctype
        self.sink = None
        self.kernel = None
        self.language = None

        if mimetype is None:
            self.mimetype = MimeTypes.guess_mimetype(self.source)
        else:
            self.mimetype = MimeTypes.get_mimetype(mimetype)


        if self.source != None:
            name, file_ext = os.path.splitext(self.source)
            self.file_ext = file_ext.lower()
        else:
            self.file_ext = None

        self.output = output
        self.setkernel(kernel)
        self._setwd()

        #Init variables not set using the constructor
        #: Use documentation mode
        self.documentationmode = False
        self.parsed = None
        self.executed = None
        self.formatted = None
        self.reader = None
        self.formatter = None
        self.theme = "skeleton"

        self.setformat(doctype)
        self.read(reader = informat)

    def _setwd(self):
        if self.output is not None:
            self.wd = os.path.dirname(self.output)
        elif parse.urlparse(self.source).scheme == "":
            self.wd = os.path.dirname(self.source)
        else:
            self.wd = "."

    def setkernel(self, kernel):
        """Set the kernel for jupyter_client"""
        self.kernel = kernel
        if kernel is not None:
            self.language = kernelspec.get_kernel_spec(kernel).language

    def getformat(self):
        """Get current format dictionary. See: http://mpastell.com/pweave/customizing.html"""
        return self.formatter.formatdict

    def updateformat(self, dict):
        """Update existing format, See: http://mpastell.com/pweave/customizing.html"""
        self.formatter.formatdict.update(dict)

    def read(self, string=None, basename="string_input", reader = None):
        """
        Parse document

        :param: None (set automatically), reader name or class object
        """
        if reader is None:
            Reader = PwebReaders.guess_reader(self.source)
        elif isinstance(reader, str):
            Reader = PwebReaders.get_reader(reader)
        else:
            Reader = reader


        if string is None:
            self.reader = Reader(file=self.source)
        else:
            self.reader = self.Reader(string=string)
            self.source = basename # non-trivial implications possible
        self.reader.parse()
        self.parsed = self.reader.getparsed()



    def run(self, Processor = None):
        """Execute code in the document"""
        if Processor is None:
            Processor = PwebProcessors.getprocessor(self.kernel)

        proc = Processor(copy.deepcopy(self.parsed),
                         self.kernel,
                         self.source,
                         self.documentationmode,
                         self.figdir,
                         self.wd
                        )
        proc.run()
        self.executed = proc.getresults()

    def setformat(self, doctype = None, Formatter = None):
        """
        Set formatter by name or class. You can pass either

        :param doctype: The name of Pweave output format
        :param Formatter: Formatter class
        """

        if doctype is not None:
            Formatter = PwebFormats.getFormatter(doctype)
        elif Formatter is not None:
            Formatter = Formatter
        elif self.doctype is None:
            Formatter = PwebFormats.getFormatter(PwebFormats.guessFromFilename(self.source))
        else:
            Formatter = PwebFormats.getFormatter(self.doctype)

        self.formatter = Formatter([],
                                   kernel = self.kernel,
                                   language = self.language,
                                   mimetype = self.mimetype.type,
                                   source = self.source,
                                   theme = self.theme,
                                   figdir = self.figdir,
                                   wd = self.wd)


    def format(self):
        """Format executed code for writing. """
        self.formatter.executed = copy.deepcopy(self.executed)
        self.formatter.format()
        self.formatted = self.formatter.getformatted()

    def setsink(self):
        if self.output is not None:
            self.sink = self.output
        elif parse.urlparse(self.source).scheme == "":
            self.sink = os.path.splitext(self.source)[0] + '.' + self.formatter.file_ext
        else:
            url_path = parse.urlparse(self.source).path
            self.sink = os.path.splitext(os.path.basename(url_path))[0] + '.' + self.formatter.file_ext

    def write(self):
        """Write formatted code to file"""
        self.setsink()

        self._writeToSink(self.formatted.replace("\r", ""))
        self._print('Weaved {src} to {dst}\n'.format(src=self.source,
                                                        dst=self.sink))

    def _print(self, msg):
        sys.stdout.write(msg)

    def _writeToSink(self, data):
        f = io.open(self.sink, 'wt', encoding='utf-8')
        f.write(data)
        f.close()

    def weave(self):
        """Weave the document, equals -> parse, run, format, write"""
        self.run()
        self.format()
        self.write()

    def tangle(self):
        """Tangle the document"""
        if self.output is None:
            target = os.path.join(self.wd, self.basename + '.py')
        code = [x for x in self.parsed if x['type'] == 'code']
        main = '\nif __name__ == "__main__":'
        for x in code:
            if 'main' in x['options'] and x['options']['main']:
                x['content'] = x['content'].replace("\n", "\n    ")
                x['content'] = "".join([main, x['content']])
        code = [x['content'] for x in code]
        f = open(target, 'w')
        f.write('\n'.join(code) + "\n")
        f.close()
        print('Tangled code from {src} to {dst}'.format(src=self.source,
                                                              dst=target))