24 A list of insulting words of some kind 29 \param id A WordListId (expanded with word_list_id()) 30 \param words An iterable containing words to add to the list 44 Appends a word to the list 48 def get(self, max_count=1, min_count=None):
50 Retrieves a random subset of words 51 \param max_count Maximum number of words to return 52 \param min_count Minimum number of words to return, 53 if omitted, returns exactly \p max_count words 55 if max_count > len(self.
words):
56 max_count = len(self.
words)
59 return random.sample(self.
words, random.randint(min_count, max_count))
63 Checks if the flags match 71 Identifier for a word list 80 Checks if the word list matches this Id 81 \param word_list a WordList object 83 return word_list.name == self.
name and word_list.check_flags(self.
flags)
88 Workaround for the lack of overloading 91 if isinstance(args[0], basestring):
93 if isinstance(args[0], WordListId):
95 if type(args[0])
is tuple
and len(args[0]) == 2:
99 raise TypeError(
"Invalid arguments to the WordListId constructor")
104 Object that can generate insults 105 \note all methods that take a WordListId argument, will expand it 110 regex_word_file = re.compile(
r'^[a-z_]+$')
112 rules_file =
"rules.json" 128 Returns a matching word list 129 \param wl_id WordListId to match the list 130 \param add if \c True, missing lists will be added to the insulter 131 \throws Exception if the list cannot be retrieved 135 if wl_id.check(word_list):
139 self.word_lists.append(
WordList(wl_id, []))
142 raise Exception(
"Word list not found: %s" % wl_id.name)
146 Loads all word lists in \p path 147 \param path The path to the directory to load 148 \note Only files matching regex_word_file will be considered 150 for basename
in os.listdir(path):
151 full = os.path.join(path, basename)
152 if basename == Insulter.rules_file:
154 with open(full)
as file:
155 rules = json.load(file)
156 for name, rule
in rules.iteritems():
160 elif os.path.isfile(full)
and self.regex_word_file.match(basename):
161 with open(full)
as file:
162 lines = filter(bool, (line.strip()
for line
in file))
167 Adds words to a word list 168 \param wl_id WordListId to match the list 169 \param words Iterable with words to be added 171 self.
word_list(wl_id,
True).words |= set(words)
173 def get(self, wl_id, max_count=1, min_count=None):
175 Retrieves a random subset of words form a word list 176 \param wl_id WordListId to match the list 177 \param max_count Maximum number of words to return, 178 note that it will be checked against the value set 180 \param min_count Minimum number of words to return, 181 if omitted, returns exactly \p max_count words 182 \see set_max(), WordList.get() 187 if max_count > self.list_max_count.get(wl_id.name, max_count):
193 Formats an insult string 195 doc =
NotQuiteXml(string,
lambda e: e.attrs.get(
"_expansion",
""))
199 for elem
in doc.contents
200 if isinstance(elem, NotQuiteXmlElement)
204 while len(new_unexpanded) != len(unexpanded)
and new_unexpanded:
205 unexpanded = new_unexpanded
207 for elem
in unexpanded:
209 new_unexpanded.append(elem)
212 def _expand_element(self, element, doc):
214 if element.tag_name
in self.
rules:
218 if "count" in element.attrs:
219 max = int(element.count)
220 elif "max" in element.attrs:
221 max = int(element.max)
222 min = int(element.attrs.get(
"min", element.max))
223 element._expansion =
" ".join(self.
get(element.tag_name, max, min))
228 def _expand_rule(self, element, doc):
229 for rule
in self.
rules[element.tag_name]:
230 pattern = rule[
"target"]
231 target = doc.element_by_id(element.target)
232 if re.match(pattern, target._expansion):
233 element._expansion = re.sub(pattern, rule[
"result"], target._expansion)
239 Set the maximum number of repetitions for get() 240 \param max_count Maximum to be set, 241 if \c None will disable the maximum limit 242 \param word_list Word list name (note: not a WordListId) 244 if word_list
is None:
246 elif max_count
is None:
254 Sets some language rules for the given identifier 256 self.
rules[name] = rules
261 Parses strings with flat xml elements intermixed with text 262 Only a very minimal subset of xml/sgml is supported 270 def __init__(self, contents=None, to_string=lambda x:
""):
272 \param contents \c None or a sting to be parsed 273 \param to_string A functor to convert NotQuiteXmlElement 283 if isinstance(contents, basestring):
288 Returns the element matching the given id 294 Returns a list of elements with the given tag name 299 if isinstance(element, NotQuiteXmlElement)
and 300 element.tag_name == name
305 Returns a list of elements having the given attribute with the given value 310 if isinstance(element, NotQuiteXmlElement)
and 311 name
in element.attrs
and element.attrs[name] == value
317 Converts the document to a string (using self.to_string for elements) 319 return "".join(str(elem)
for elem
in self.
contents)
323 elem
if type(elem)
is str
else repr(elem)
329 Parses a string into self.contents 333 def _lex_text(self, iterator):
335 Internal lexer, starting state (text) 336 yields elements for self.contents 337 \param iterator A character iterator 352 except StopIteration:
356 def _lex_entity(self, iterator):
358 Internal lexer, entity state 361 \returns A string corresponding to the entity 362 \param iterator A character iterator 371 return self._entities.get(name,
"")
373 def _lex_elem_name(self, iterator):
375 Internal lexer, element name state 377 out: /> | > | _ -> (attrs) -> (text) 378 \returns A string corresponding to the entity 379 \param iterator A character iterator 384 if ch.isspace()
or ch
in "/>":
390 def _lex_elem_attrs(self, och, iterator, element):
392 Internal lexer, element attributes state 393 in: (text) -> (element name) -> _ | > | /> 394 out: /> | > | -> (text) 395 \param och Character used to enter this state 396 \param iterator A character iterator 397 \param element Element to set the attributes to 406 elif ch.isspace()
or ch ==
"":
411 def _lex_elem_attr_name(self, och, iterator, element):
413 Internal lexer, element attribute name 414 in: (attrs) -> [not space or tag end] 415 out: = -> (attr_value) -> (attrs) 416 out: /> | > | _ -> (attrs) 417 \param och Character used to enter this state 418 \param iterator A character iterator 419 \param element Element to set the attributes to 420 \returns A lookahead character 425 if ch.isspace()
or ch
in "/>":
433 def _lex_elem_attr_value(self, name, iterator, element):
435 Internal lexer, element attribute value 437 out: (attr_name) -> =" -> (here) -> " -> (attrs) 438 out: (attr_name) -> =' -> (here) -> ' -> (attrs) 439 out: (attr_name) -> = -> (here) -> _ -> (attrs) 440 \param name Name of the attribute 441 \param iterator A character iterator 442 \param element Element to set the attributes to 443 \returns A lookahead character 448 if ch ==
'"' or ch ==
"'":
450 break_cond =
lambda char: char == delim
451 elif ch.isspace()
or ch
in "/>":
452 break_cond =
lambda char:
True 455 break_cond =
lambda char: char.isspace()
or char
in "/>" 460 while not break_cond(ch):
469 def _elem_set_attr(self, element, name, value):
471 Internal, sets an element attribute during parsing 472 \todo handle this where you can set attributes in NotQuiteXmlElement 476 element.id = value
if value
else None 478 element[name] = value
483 Non-text element in a NotQuiteXml document. 484 Attributes can be accessed with the subscript operator or as members 485 (if they don't clash with other members) 487 def __init__(self, document, tag_name, id=None, attrs={}):
489 \param document A NotQuiteXml object which contains this element 490 \param tag_name Name of the element tag in the source string 491 \param id Element id, must be unique in \p document or None 492 \param attrs Extra attribues 514 if value == self.
_id:
521 if value
in self.document.elements_with_id:
522 raise KeyError(
"ID already in use: %s" % value)
524 if self.
_id is not None:
525 del self.document.elements_with_id[self.
_id]
527 self.document.elements_with_id[value] = self
531 if self.
_id is not None:
532 del self.document.elements_with_id[self.
_id]
536 return self.
attrs[key]
539 self.
attrs[key] = value
547 except AttributeError:
548 if name
in self.
attrs:
549 return self.
attrs[name]
554 if name
in dir(self)
or "_id" not in dir(self):
555 super(NotQuiteXmlElement, self).
__setattr__(name, value)
557 self.
attrs[name] = value
562 except AttributeError:
563 if name
in self.
attrs:
570 Converts the element to a string using the document to_string attribute 572 return self.document.to_string(self)
575 return "<%s%s%s/>" % (
577 " id=\"%s\"" % self.
_id if self.
_id is not None else "",
578 "".join(
" %s=\"%s\"" % attr
for attr
in self.attrs.iteritems() )
def word_list(self, wl_id, add=False)
Returns a matching word list.
to_string
Functor to convert NotQuiteXmlElement objects to a string.
list_max_count
Maximum number of repetitions allowed for a specific word list.
def check(self, word_list)
Checks if the word list matches this Id.
def __init__(self, document, tag_name, id=None, attrs={})
elements_with_id
Elements with an ID.
def _lex_elem_attrs(self, och, iterator, element)
Internal lexer, element attributes state in: (text) -> (element name) -> _ | > | /> out: /> | > | -> ...
def _elem_set_attr(self, element, name, value)
Internal, sets an element attribute during parsing.
def check_flags(self, flags)
Checks if the flags match.
words
Set of words in the list.
def add_word(self, word)
Appends a word to the list.
def __init__(self, contents=None, to_string=lambda x:"")
def __init__(self, name, flags=0)
def add_words(self, wl_id, words)
Adds words to a word list.
def _lex_entity(self, iterator)
Internal lexer, entity state in: (text) -> & out: ; -> (text)
def _lex_elem_attr_value(self, name, iterator, element)
Internal lexer, element attribute value in: (attr_name) -> = out: (attr_name) -> =" -> (here) -> " ->...
def set_rules(self, name, rules)
Sets some language rules for the given identifier.
def __setattr__(self, name, value)
def __getitem__(self, key)
def _expand_element(self, element, doc)
def __str__(self)
Converts the element to a string using the document to_string attribute.
def set_max(self, max_count, word_list=None)
Set the maximum number of repetitions for get()
Object that can generate insults.
def __getattr__(self, name)
name
Name of the word list.
def __delitem__(self, key)
def word_list_id(args)
Workaround for the lack of overloading.
def __setitem__(self, key, value)
def parse_string(self, string)
Parses a string into self.contents.
Non-text element in a NotQuiteXml document.
def _lex_text(self, iterator)
Internal lexer, starting state (text) yields elements for self.contents.
flags
Flags fot the set of words.
def get(self, wl_id, max_count=1, min_count=None)
Retrieves a random subset of words form a word list.
def __str__(self)
Converts the document to a string (using self.to_string for elements)
def get(self, max_count=1, min_count=None)
Retrieves a random subset of words.
max_count
Maximum number of repetitions allowed.
def load_directory(self, path)
Loads all word lists in path.
Parses strings with flat xml elements intermixed with text Only a very minimal subset of xml/sgml is ...
def __init__(self, id, words=[])
A list of insulting words of some kind.
def __delattr__(self, name)
def elements_by_tag_name(self, name)
Returns a list of elements with the given tag name.
contents
List mixing strings and NotQuiteXmlElement elements.
def _lex_elem_attr_name(self, och, iterator, element)
Internal lexer, element attribute name in: (attrs) -> [not space or tag end] out: = -> (attr_value) -...
def elements_by_attribute(self, name, value)
Returns a list of elements having the given attribute with the given value.
def format(self, string)
Formats an insult string.
def _lex_elem_name(self, iterator)
Internal lexer, element name state in: (text) -> < out: /> | > | _ -> (attrs) -> (text) ...
def element_by_id(self, id)
Returns the element matching the given id.
Identifier for a word list.
def _expand_rule(self, element, doc)
word_lists
Word lists to look up.