Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aws
GitHub Repository: aws/aws-cli
Path: blob/develop/awscli/bcdoc/restdoc.py
1566 views
1
# Copyright 2012-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
#
3
# Licensed under the Apache License, Version 2.0 (the "License"). You
4
# may not use this file except in compliance with the License. A copy of
5
# the License is located at
6
#
7
# http://aws.amazon.com/apache2.0/
8
#
9
# or in the "license" file accompanying this file. This file is
10
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
# ANY KIND, either express or implied. See the License for the specific
12
# language governing permissions and limitations under the License.
13
import logging
14
15
from botocore.compat import OrderedDict
16
from awscli.bcdoc.docstringparser import DocStringParser
17
from awscli.bcdoc.style import ReSTStyle
18
19
LOG = logging.getLogger('bcdocs')
20
21
22
class ReSTDocument(object):
23
24
def __init__(self, target='man'):
25
self.style = ReSTStyle(self)
26
self.target = target
27
self.parser = DocStringParser(self)
28
self.keep_data = True
29
self.do_translation = False
30
self.translation_map = {}
31
self.hrefs = {}
32
self._writes = []
33
self._last_doc_string = None
34
35
def _write(self, s):
36
if self.keep_data and s is not None:
37
self._writes.append(s)
38
39
def write(self, content):
40
"""
41
Write content into the document.
42
"""
43
self._write(content)
44
45
def writeln(self, content):
46
"""
47
Write content on a newline.
48
"""
49
self._write('%s%s\n' % (self.style.spaces(), content))
50
51
def peek_write(self):
52
"""
53
Returns the last content written to the document without
54
removing it from the stack.
55
"""
56
return self._writes[-1]
57
58
def pop_write(self):
59
"""
60
Removes and returns the last content written to the stack.
61
"""
62
return self._writes.pop()
63
64
def push_write(self, s):
65
"""
66
Places new content on the stack.
67
"""
68
self._writes.append(s)
69
70
def find_last_write(self, content):
71
"""
72
Returns the index of the last occurrence of the content argument
73
in the stack, or returns None if content is not on the stack.
74
"""
75
try:
76
return len(self._writes) - self._writes[::-1].index(content) - 1
77
except ValueError:
78
return None
79
80
def insert_write(self, index, content):
81
"""
82
Inserts the content argument to the stack directly before the
83
supplied index.
84
"""
85
self._writes.insert(index, content)
86
87
def getvalue(self):
88
"""
89
Returns the current content of the document as a string.
90
"""
91
if self.hrefs:
92
self.style.new_paragraph()
93
for refname, link in self.hrefs.items():
94
self.style.link_target_definition(refname, link)
95
return ''.join(self._writes).encode('utf-8')
96
97
def translate_words(self, words):
98
return [self.translation_map.get(w, w) for w in words]
99
100
def handle_data(self, data):
101
if data and self.keep_data:
102
self._write(data)
103
104
def include_doc_string(self, doc_string):
105
if doc_string:
106
try:
107
start = len(self._writes)
108
self.parser.feed(doc_string)
109
self.parser.close()
110
end = len(self._writes)
111
self._last_doc_string = (start, end)
112
except Exception:
113
LOG.debug('Error parsing doc string', exc_info=True)
114
LOG.debug(doc_string)
115
116
def remove_last_doc_string(self):
117
# Removes all writes inserted by last doc string
118
if self._last_doc_string is not None:
119
start, end = self._last_doc_string
120
del self._writes[start:end]
121
122
def write_from_file(self, filename):
123
with open(filename, 'r') as f:
124
for line in f.readlines():
125
self.writeln(line.strip())
126
127
128
class DocumentStructure(ReSTDocument):
129
def __init__(self, name, section_names=None, target='man', context=None):
130
"""Provides a Hierarichial structure to a ReSTDocument
131
132
You can write to it similiar to as you can to a ReSTDocument but
133
has an innate structure for more orginaztion and abstraction.
134
135
:param name: The name of the document
136
:param section_names: A list of sections to be included
137
in the document.
138
:param target: The target documentation of the Document structure
139
:param context: A dictionary of data to store with the strucuture. These
140
are only stored per section not the entire structure.
141
"""
142
super(DocumentStructure, self).__init__(target=target)
143
self._name = name
144
self._structure = OrderedDict()
145
self._path = [self._name]
146
self._context = {}
147
if context is not None:
148
self._context = context
149
if section_names is not None:
150
self._generate_structure(section_names)
151
152
@property
153
def name(self):
154
"""The name of the document structure"""
155
return self._name
156
157
@property
158
def path(self):
159
"""
160
A list of where to find a particular document structure in the
161
overlying document structure.
162
"""
163
return self._path
164
165
@path.setter
166
def path(self, value):
167
self._path = value
168
169
@property
170
def available_sections(self):
171
return list(self._structure)
172
173
@property
174
def context(self):
175
return self._context
176
177
def _generate_structure(self, section_names):
178
for section_name in section_names:
179
self.add_new_section(section_name)
180
181
def add_new_section(self, name, context=None):
182
"""Adds a new section to the current document structure
183
184
This document structure will be considered a section to the
185
current document structure but will in itself be an entirely
186
new document structure that can be written to and have sections
187
as well
188
189
:param name: The name of the section.
190
:param context: A dictionary of data to store with the strucuture. These
191
are only stored per section not the entire structure.
192
:rtype: DocumentStructure
193
:returns: A new document structure to add to but lives as a section
194
to the document structure it was instantiated from.
195
"""
196
# Add a new section
197
section = self.__class__(name=name, target=self.target,
198
context=context)
199
section.path = self.path + [name]
200
# Indent the section apporpriately as well
201
section.style.indentation = self.style.indentation
202
section.translation_map = self.translation_map
203
section.hrefs = self.hrefs
204
self._structure[name] = section
205
return section
206
207
def get_section(self, name):
208
"""Retrieve a section"""
209
return self._structure[name]
210
211
def delete_section(self, name):
212
"""Delete a section"""
213
del self._structure[name]
214
215
def flush_structure(self):
216
"""Flushes a doc structure to a ReSTructed string
217
218
The document is flushed out in a DFS style where sections and their
219
subsections' values are added to the string as they are visited.
220
"""
221
# We are at the root flush the links at the beginning of the
222
# document
223
if len(self.path) == 1:
224
if self.hrefs:
225
self.style.new_paragraph()
226
for refname, link in self.hrefs.items():
227
self.style.link_target_definition(refname, link)
228
value = self.getvalue()
229
for name, section in self._structure.items():
230
value += section.flush_structure()
231
return value
232
233
def getvalue(self):
234
return ''.join(self._writes).encode('utf-8')
235
236
def remove_all_sections(self):
237
self._structure = OrderedDict()
238
239
def clear_text(self):
240
self._writes = []
241
242