FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
plotdevice/plotdevice/util/kgp.py at v1.0.0 · plotdevice/plotdevice · GitHub
plotdevice
plotdevice
Repository navigation
Code
Issues
10
(10)
Pull requests
4
(4)
Discussions
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
plotdevice
/
plotdevice
/
util
/
kgp.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
296 lines (245 loc) · 9.78 KB
Breadcrumbs
plotdevice
/
plotdevice
/
util
/
kgp.py
Copy path
File metadata and controls
296 lines (245 loc) · 9.78 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
#!/usr/bin/env python2
"""Kant Generator for Python
Generates mock philosophy based on a context-free grammar
Usage: python kgp.py [options] [source]
Options:
-g ..., --grammar=... use specified grammar file or URL
-h, --help show this help
-d show debugging information while parsing
Examples:
kgp.py generates several paragraphs of Kantian philosophy
kgp.py -g husserl.xml generates several paragraphs of Husserl
kpg.py "<xref id='paragraph'/>" generates a paragraph of Kant
kgp.py template.xml reads from template.xml to decide what to generate
This program is part of "Dive Into Python", a free Python book for
experienced programmers. Visit http://diveintopython.org/ for the
latest version.
"""
__author__
=
"Mark Pilgrim (f8dy@diveintopython.org)"
__version__
=
"$Revision: 1.3 $"
__date__
=
"$Date: 2002/05/28 17:05:23 $"
__copyright__
=
"Copyright (c) 2001 Mark Pilgrim"
__license__
=
"Python"
from
xml
.
dom
import
minidom
import
random
import
sys
import
getopt
_debug
=
0
def
openAnything
(
source
):
"""URI, filename, or string --> stream
This function lets you define parsers that take any input source
(URL, pathname to local or network file, or actual data as a string)
and deal with it in a uniform manner. Returned object is guaranteed
to have all the basic stdio read methods (read, readline, readlines).
Just .close() the object when you're done with it.
Examples:
>>> from xml.dom import minidom
>>> sock = openAnything("http://localhost/kant.xml")
>>> doc = minidom.parse(sock)
>>> sock.close()
>>> sock = openAnything("c:
\\
inetpub
\\
wwwroot
\\
kant.xml")
>>> doc = minidom.parse(sock)
>>> sock.close()
>>> sock = openAnything("<ref id='conjunction'><text>and</text><text>or</text></ref>")
>>> doc = minidom.parse(sock)
>>> sock.close()
"""
if
hasattr
(
source
,
"read"
):
return
source
if
source
==
"-"
:
import
sys
return
sys
.
stdin
# try to open with urllib (if source is http, ftp, or file URL)
import
urllib
.
request
try
:
return
urllib
.
request
.
urlopen
(
source
)
except
(
IOError
,
OSError
,
ValueError
):
pass
# try to open with native open function (if source is pathname)
try
:
return
open
(
source
)
except
(
IOError
,
OSError
):
pass
# treat source as string
import
io
return
io
.
StringIO
(
str
(
source
))
class
NoSourceError
(
Exception
):
pass
class
KantGenerator
:
"""generates mock philosophy based on a context-free grammar"""
def
__init__
(
self
,
grammar
,
source
=
None
):
self
.
loadGrammar
(
grammar
)
self
.
loadSource
(
source
and
source
or
self
.
getDefaultSource
())
self
.
refresh
()
def
_load
(
self
,
source
):
"""load XML input source, return parsed XML document
- a URL of a remote XML file ("http://diveintopython.org/kant.xml")
- a filename of a local XML file ("~/diveintopython/common/py/kant.xml")
- standard input ("-")
- the actual XML document, as a string
"""
sock
=
openAnything
(
source
)
xmldoc
=
minidom
.
parse
(
sock
).
documentElement
sock
.
close
()
return
xmldoc
def
loadGrammar
(
self
,
grammar
):
"""load context-free grammar"""
self
.
grammar
=
self
.
_load
(
grammar
)
self
.
refs
=
{}
for
ref
in
self
.
grammar
.
getElementsByTagName
(
"ref"
):
self
.
refs
[
ref
.
attributes
[
"id"
].
value
]
=
ref
def
loadSource
(
self
,
source
):
"""load source"""
self
.
source
=
self
.
_load
(
source
)
def
getDefaultSource
(
self
):
"""guess default source of the current grammar
The default source will be one of the <ref>s that is not
cross-referenced. This sounds complicated but it's not.
Example: The default source for kant.xml is
"<xref id='section'/>", because 'section' is the one <ref>
that is not <xref>'d anywhere in the grammar.
In most grammars, the default source will produce the
longest (and most interesting) output.
"""
xrefs
=
{}
for
xref
in
self
.
grammar
.
getElementsByTagName
(
"xref"
):
xrefs
[
xref
.
attributes
[
"id"
].
value
]
=
1
xrefs
=
xrefs
.
keys
()
standaloneXrefs
=
[
e
for
e
in
self
.
refs
.
keys
()
if
e
not
in
xrefs
]
if
not
standaloneXrefs
:
raise
NoSourceError
(
"can't guess source, and no source specified"
)
return
'<xref id="%s"/>'
%
random
.
choice
(
standaloneXrefs
)
def
reset
(
self
):
"""reset parser"""
self
.
pieces
=
[]
self
.
capitalizeNextWord
=
0
def
refresh
(
self
):
"""reset output buffer, re-parse entire source file, and return output
Since parsing involves a good deal of randomness, this is an
easy way to get new output without having to reload a grammar file
each time.
"""
self
.
reset
()
self
.
parse
(
self
.
source
)
return
self
.
output
()
def
output
(
self
):
"""output generated text"""
return
""
.
join
(
self
.
pieces
)
def
randomChildElement
(
self
,
node
):
"""choose a random child element of a node
This is a utility method used by do_xref and do_choice.
"""
choices
=
[
e
for
e
in
node
.
childNodes
if
e
.
nodeType
==
e
.
ELEMENT_NODE
]
chosen
=
random
.
choice
(
choices
)
if
_debug
:
sys
.
stderr
.
write
(
'%s available choices: %s
\n
'
%
\
(
len
(
choices
), [
e
.
toxml
()
for
e
in
choices
]))
sys
.
stderr
.
write
(
'Chosen: %s
\n
'
%
chosen
.
toxml
())
return
chosen
def
parse
(
self
,
node
):
"""parse a single XML node
A parsed XML document (from minidom.parse) is a tree of nodes
of various types. Each node is represented by an instance of the
corresponding Python class (Element for a tag, Text for
text data, Document for the top-level document). The following
statement constructs the name of a class method based on the type
of node we're parsing ("parse_Element" for an Element node,
"parse_Text" for a Text node, etc.) and then calls the method.
"""
parseMethod
=
getattr
(
self
,
"parse_%s"
%
node
.
__class__
.
__name__
)
parseMethod
(
node
)
def
parse_Document
(
self
,
node
):
"""parse the document node
The document node by itself isn't interesting (to us), but
its only child, node.documentElement, is: it's the root node
of the grammar.
"""
self
.
parse
(
node
.
documentElement
)
def
parse_Text
(
self
,
node
):
"""parse a text node
The text of a text node is usually added to the output buffer
verbatim. The one exception is that <p class='sentence'> sets
a flag to capitalize the first letter of the next word. If
that flag is set, we capitalize the text and reset the flag.
"""
text
=
node
.
data
if
self
.
capitalizeNextWord
:
self
.
pieces
.
append
(
text
[
0
].
upper
())
self
.
pieces
.
append
(
text
[
1
:])
self
.
capitalizeNextWord
=
0
else
:
self
.
pieces
.
append
(
text
)
def
parse_Element
(
self
,
node
):
"""parse an element
An XML element corresponds to an actual tag in the source:
<xref id='...'>, <p chance='...'>, <choice>, etc.
Each element type is handled in its own method. Like we did in
parse(), we construct a method name based on the name of the
element ("do_xref" for an <xref> tag, etc.) and
call the method.
"""
handlerMethod
=
getattr
(
self
,
"do_%s"
%
node
.
tagName
)
handlerMethod
(
node
)
def
parse_Comment
(
self
,
node
):
"""parse a comment
The grammar can contain XML comments, but we ignore them
"""
pass
def
do_xref
(
self
,
node
):
"""handle <xref id='...'> tag
An <xref id='...'> tag is a cross-reference to a <ref id='...'>
tag. <xref id='sentence'/> evaluates to a randomly chosen child of
<ref id='sentence'>.
"""
id
=
node
.
attributes
[
"id"
].
value
self
.
parse
(
self
.
randomChildElement
(
self
.
refs
[
id
]))
def
do_p
(
self
,
node
):
"""handle <p> tag
The <p> tag is the core of the grammar. It can contain almost
anything: freeform text, <choice> tags, <xref> tags, even other
<p> tags. If a "class='sentence'" attribute is found, a flag
is set and the next word will be capitalized. If a "chance='X'"
attribute is found, there is an X% chance that the tag will be
evaluated (and therefore a (100-X)% chance that it will be
completely ignored)
"""
keys
=
node
.
attributes
.
keys
()
if
"class"
in
keys
:
if
node
.
attributes
[
"class"
].
value
==
"sentence"
:
self
.
capitalizeNextWord
=
1
if
"chance"
in
keys
:
chance
=
int
(
node
.
attributes
[
"chance"
].
value
)
doit
=
(
chance
>
random
.
randrange
(
100
))
else
:
doit
=
1
if
doit
:
for
child
in
node
.
childNodes
:
self
.
parse
(
child
)
def
do_choice
(
self
,
node
):
"""handle <choice> tag
A <choice> tag contains one or more <p> tags. One <p> tag
is chosen at random and evaluated; the rest are ignored.
"""
self
.
parse
(
self
.
randomChildElement
(
node
))
def
usage
():
print
(
__doc__
)
def
main
(
argv
):
grammar
=
"kant.xml"
try
:
opts
,
args
=
getopt
.
getopt
(
argv
,
"hg:d"
, [
"help"
,
"grammar="
])
except
getopt
.
GetoptError
:
usage
()
sys
.
exit
(
2
)
for
opt
,
arg
in
opts
:
if
opt
in
(
"-h"
,
"--help"
):
usage
()
sys
.
exit
()
elif
opt
==
'-d'
:
global
_debug
_debug
=
1
elif
opt
in
(
"-g"
,
"--grammar"
):
grammar
=
arg
source
=
""
.
join
(
args
)
k
=
KantGenerator
(
grammar
,
source
)
print
(
k
.
output
())
if
__name__
==
"__main__"
:
main
(
sys
.
argv
[
1
:])
Back
|
FazBrowse Home
|
New Git URL