Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 39544
1
#!/usr/bin/env python3
2
# -*- coding: utf8 -*-
3
4
#####################################################################################
5
# CoCalc Examples - Documentation Files Compiler #
6
# #
7
# Copyright (C) 2015 -- 2017, SageMath, Inc. #
8
# #
9
# Distributed under the terms of the GNU General Public License (GPL), version 2+ #
10
# #
11
# http://www.gnu.org/licenses/ #
12
#####################################################################################
13
14
import os, sys
15
16
# make it python 2 and 3 compatible (although, to be clear, it is supposed to be py3 only)
17
if (sys.version_info > (3, 0)):
18
mystr = str
19
else:
20
mystr = basestring
21
22
from os.path import abspath, dirname, normpath, exists, join
23
from os import makedirs, walk
24
from shutil import rmtree
25
import yaml
26
import json
27
import re
28
from codecs import open
29
from collections import defaultdict
30
31
""" # TODO enable hashtags later
32
hashtag_re = re.compile(r'#([a-zA-Z].+?\b)')
33
def process_hashtags(match):
34
ht = match.group(1)
35
return "<a class='webapp-examples-hashtag' href='{0}'>#{0}</a>".format(ht)
36
"""
37
38
def process_category(doc):
39
cats = doc["category"]
40
if isinstance(cats, (list, tuple)):
41
assert len(cats) == 2
42
elif isinstance(cats, mystr):
43
cats = cats.split("/", 1)
44
else:
45
raise Exception("What is id '%s' supposed to be?" % cats)
46
return [c.strip().title() for c in cats]
47
48
def process_doc(doc, input_fn):
49
"""
50
This processes one document entry and returns the suitable datastructure for later conversion to JSON
51
"""
52
#if not all(_ in doc.keys() for _ in ["title", "code", "descr"]):
53
# raise Exception("keyword missing in %s in %s" % (doc, input_fn))
54
title = doc["title"]
55
code = doc["code"]
56
description = doc["descr"] # hashtag_re.sub(process_hashtags, doc["descr"])
57
body = [code, description]
58
if "attr" in doc:
59
body.append(doc["attr"])
60
return title, body
61
62
def examples_data(input_dir, output_fn):
63
input_dir = abspath(normpath(input_dir))
64
examples_json = abspath(normpath(output_fn))
65
output_dir = dirname(examples_json)
66
print(output_dir)
67
#print(input_dir, output_dir)
68
69
# this implicitly defines all known languages
70
recursive_dict = lambda : defaultdict(recursive_dict)
71
examples = {
72
"sage": recursive_dict(),
73
"python": recursive_dict(),
74
"r": recursive_dict(),
75
"cython": recursive_dict(),
76
"gap": recursive_dict()
77
}
78
79
for root, _, files in walk(input_dir):
80
for fn in filter(lambda _ : _.lower().endswith("yaml"), files):
81
input_fn = join(root, fn)
82
data = yaml.load_all(open(input_fn, "r", "utf8").read())
83
84
language = entries = lvl1 = lvl2 = titles = None # must be set first in the "category" case
85
86
for doc in data:
87
if doc is None:
88
continue
89
90
processed = False
91
92
if "language" in doc:
93
language = doc["language"]
94
if language not in examples.keys():
95
raise Exception("Language %s not known. Fix first document in %s" % (language, input_fn))
96
processed = True
97
98
if "category" in doc: # setting both levels of the category and re-setting entries and titles
99
lvl1, lvl2 = process_category(doc)
100
if lvl2 in examples[language][lvl1]:
101
raise Exception("Category level2 '%s' already exists (error in %s)" % (lvl2, input_fn))
102
entries = examples[language][lvl1][lvl2] = []
103
titles = set()
104
processed = True
105
106
if all(_ in doc.keys() for _ in ["title", "code", "descr"]):
107
# we have an actual document entry, append it in the original ordering as a tuple.
108
title, body = process_doc(doc, input_fn)
109
if title in titles:
110
raise Exception("Duplicate title '{title}' in {language}::{lvl1}/{lvl2} of {input_fn}".format(**locals()))
111
entries.append([title, body])
112
titles.add(title)
113
processed = True
114
115
# if False, malformatted document
116
if not processed: # bad document
117
raise Exception("This document is not well formatted (wrong keys, etc.)\n%s" % doc)
118
119
if not os.path.exists(output_dir):
120
print("Creating output directory '%s'" % output_dir)
121
os.makedirs(output_dir)
122
123
with open(examples_json, "w", "utf8") as f_out:
124
# sorted keys to de-randomize output (stable representation when kept it in Git)
125
json.dump(examples, f_out, ensure_ascii=True, sort_keys=True, indent=1)
126
127
if __name__ == "__main__":
128
if len(sys.argv) != 3:
129
print("Usage: %s <input-directory of *.yaml files> <ouput-file (usually 'examples.json')>" % sys.argv[0])
130
sys.exit(1)
131
examples_data(sys.argv[1], sys.argv[2])
132
133
134