@@ -1,5 +1,6 @@ | |||
v0.6 (unreleased): | |||
- Fixed manual construction of Node objects, previously unsupported. (#214) | |||
- Fixed Wikicode transformation methods (replace(), remove(), etc.) when passed | |||
an empty section as an argument. (#212) | |||
@@ -7,6 +7,8 @@ v0.6 | |||
Unreleased | |||
(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.5.2...develop>`__): | |||
- Fixed manual construction of Node objects, previously unsupported. | |||
(`#214 <https://github.com/earwig/mwparserfromhell/issues/214>`_) | |||
- Fixed :class:`.Wikicode` transformation methods (:meth:`.Wikicode.replace`, | |||
:meth:`.Wikicode.remove`, etc.) when passed an empty section as an argument. | |||
(`#212 <https://github.com/earwig/mwparserfromhell/issues/212>`_) | |||
@@ -1,6 +1,6 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
@@ -33,8 +33,8 @@ class Argument(Node): | |||
def __init__(self, name, default=None): | |||
super(Argument, self).__init__() | |||
self._name = name | |||
self._default = default | |||
self.name = name | |||
self.default = default | |||
def __unicode__(self): | |||
start = "{{{" + str(self.name) | |||
@@ -1,6 +1,6 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
@@ -32,10 +32,10 @@ class Comment(Node): | |||
def __init__(self, contents): | |||
super(Comment, self).__init__() | |||
self._contents = contents | |||
self.contents = contents | |||
def __unicode__(self): | |||
return "<!--" + str(self.contents) + "-->" | |||
return "<!--" + self.contents + "-->" | |||
@property | |||
def contents(self): | |||
@@ -1,6 +1,6 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
@@ -33,9 +33,9 @@ class ExternalLink(Node): | |||
def __init__(self, url, title=None, brackets=True): | |||
super(ExternalLink, self).__init__() | |||
self._url = url | |||
self._title = title | |||
self._brackets = brackets | |||
self.url = url | |||
self.title = title | |||
self.brackets = brackets | |||
def __unicode__(self): | |||
if self.brackets: | |||
@@ -1,6 +1,6 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
@@ -37,16 +37,15 @@ class Attribute(StringMixIn): | |||
""" | |||
def __init__(self, name, value=None, quotes='"', pad_first=" ", | |||
pad_before_eq="", pad_after_eq="", check_quotes=True): | |||
pad_before_eq="", pad_after_eq=""): | |||
super(Attribute, self).__init__() | |||
if check_quotes and not quotes and self._value_needs_quotes(value): | |||
raise ValueError("given value {!r} requires quotes".format(value)) | |||
self._name = name | |||
self._value = value | |||
self._quotes = quotes | |||
self._pad_first = pad_first | |||
self._pad_before_eq = pad_before_eq | |||
self._pad_after_eq = pad_after_eq | |||
self.name = name | |||
self._quotes = None | |||
self.value = value | |||
self.quotes = quotes | |||
self.pad_first = pad_first | |||
self.pad_before_eq = pad_before_eq | |||
self.pad_after_eq = pad_after_eq | |||
def __unicode__(self): | |||
result = self.pad_first + str(self.name) + self.pad_before_eq | |||
@@ -59,10 +58,17 @@ class Attribute(StringMixIn): | |||
@staticmethod | |||
def _value_needs_quotes(val): | |||
"""Return the preferred quotes for the given value, or None.""" | |||
if val and any(char.isspace() for char in val): | |||
return ('"' in val and "'" in val) or ("'" if '"' in val else '"') | |||
return None | |||
"""Return valid quotes for the given value, or None if unneeded.""" | |||
if not val: | |||
return None | |||
val = "".join(str(node) for node in val.filter_text(recursive=False)) | |||
if not any(char.isspace() for char in val): | |||
return None | |||
if "'" in val and '"' not in val: | |||
return '"' | |||
if '"' in val and "'" not in val: | |||
return "'" | |||
return "\"'" # Either acceptable, " preferred over ' | |||
def _set_padding(self, attr, value): | |||
"""Setter for the value of a padding attribute.""" | |||
@@ -123,8 +129,8 @@ class Attribute(StringMixIn): | |||
else: | |||
code = parse_anything(newval) | |||
quotes = self._value_needs_quotes(code) | |||
if quotes in ['"', "'"] or (quotes is True and not self.quotes): | |||
self._quotes = quotes | |||
if quotes and (not self.quotes or self.quotes not in quotes): | |||
self._quotes = quotes[0] | |||
self._value = code | |||
@quotes.setter | |||
@@ -1,6 +1,6 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
@@ -40,11 +40,9 @@ class Parameter(StringMixIn): | |||
def __init__(self, name, value, showkey=True): | |||
super(Parameter, self).__init__() | |||
if not showkey and not self.can_hide_key(name): | |||
raise ValueError("key {!r} cannot be hidden".format(name)) | |||
self._name = name | |||
self._value = value | |||
self._showkey = showkey | |||
self.name = name | |||
self.value = value | |||
self.showkey = showkey | |||
def __unicode__(self): | |||
if self.showkey: | |||
@@ -83,5 +81,6 @@ class Parameter(StringMixIn): | |||
def showkey(self, newval): | |||
newval = bool(newval) | |||
if not newval and not self.can_hide_key(self.name): | |||
raise ValueError("parameter key cannot be hidden") | |||
raise ValueError("parameter key {!r} cannot be hidden".format( | |||
self.name)) | |||
self._showkey = newval |
@@ -1,6 +1,6 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
@@ -33,8 +33,8 @@ class Heading(Node): | |||
def __init__(self, title, level): | |||
super(Heading, self).__init__() | |||
self._title = title | |||
self._level = level | |||
self.title = title | |||
self.level = level | |||
def __unicode__(self): | |||
return ("=" * self.level) + str(self.title) + ("=" * self.level) | |||
@@ -1,6 +1,6 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
@@ -38,28 +38,20 @@ class Tag(Node): | |||
closing_tag=None, wiki_style_separator=None, | |||
closing_wiki_markup=None): | |||
super(Tag, self).__init__() | |||
self._tag = tag | |||
if contents is None and not self_closing: | |||
self._contents = parse_anything("") | |||
else: | |||
self._contents = contents | |||
self.tag = tag | |||
self.contents = contents | |||
self._attrs = attrs if attrs else [] | |||
self._wiki_markup = wiki_markup | |||
self._self_closing = self_closing | |||
self._invalid = invalid | |||
self._implicit = implicit | |||
self._padding = padding | |||
if closing_tag: | |||
self._closing_tag = closing_tag | |||
else: | |||
self._closing_tag = tag | |||
self._wiki_style_separator = wiki_style_separator | |||
self._closing_wiki_markup = None | |||
self.wiki_markup = wiki_markup | |||
self.self_closing = self_closing | |||
self.invalid = invalid | |||
self.implicit = implicit | |||
self.padding = padding | |||
if closing_tag is not None: | |||
self.closing_tag = closing_tag | |||
self.wiki_style_separator = wiki_style_separator | |||
if closing_wiki_markup is not None: | |||
self._closing_wiki_markup = closing_wiki_markup | |||
elif wiki_markup and not self_closing: | |||
self._closing_wiki_markup = wiki_markup | |||
else: | |||
self._closing_wiki_markup = None | |||
self.closing_wiki_markup = closing_wiki_markup | |||
def __unicode__(self): | |||
if self.wiki_markup: | |||
@@ -69,10 +61,10 @@ class Tag(Node): | |||
attrs = "" | |||
padding = self.padding or "" | |||
separator = self.wiki_style_separator or "" | |||
close = self.closing_wiki_markup or "" | |||
if self.self_closing: | |||
return self.wiki_markup + attrs + padding + separator | |||
else: | |||
close = self.closing_wiki_markup or "" | |||
return self.wiki_markup + attrs + padding + separator + \ | |||
str(self.contents) + close | |||
@@ -93,10 +85,10 @@ class Tag(Node): | |||
yield attr.name | |||
if attr.value is not None: | |||
yield attr.value | |||
if self.contents: | |||
if not self.self_closing: | |||
yield self.contents | |||
if not self.self_closing and not self.wiki_markup and self.closing_tag: | |||
yield self.closing_tag | |||
if not self.wiki_markup and self.closing_tag: | |||
yield self.closing_tag | |||
def __strip__(self, **kwargs): | |||
if self.contents and is_visible(self.tag): | |||
@@ -1,6 +1,6 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2012-2017 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
@@ -38,7 +38,7 @@ class Template(Node): | |||
def __init__(self, name, params=None): | |||
super(Template, self).__init__() | |||
self._name = name | |||
self.name = name | |||
if params: | |||
self._params = params | |||
else: | |||
@@ -108,7 +108,7 @@ class Template(Node): | |||
def _blank_param_value(value): | |||
"""Remove the content from *value* while keeping its whitespace. | |||
Replace *value*\ 's nodes with two text nodes, the first containing | |||
Replace *value*\\ 's nodes with two text nodes, the first containing | |||
whitespace from before its content and the second containing whitespace | |||
from after its content. | |||
""" | |||
@@ -1,6 +1,6 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
@@ -32,7 +32,7 @@ class Text(Node): | |||
def __init__(self, value): | |||
super(Text, self).__init__() | |||
self._value = value | |||
self.value = value | |||
def __unicode__(self): | |||
return self.value | |||
@@ -1,6 +1,6 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
@@ -33,8 +33,8 @@ class Wikilink(Node): | |||
def __init__(self, title, text=None): | |||
super(Wikilink, self).__init__() | |||
self._title = title | |||
self._text = text | |||
self.title = title | |||
self.text = text | |||
def __unicode__(self): | |||
if self.text is not None: | |||
@@ -48,7 +48,7 @@ def _add_handler(token_type): | |||
class Builder(object): | |||
"""Builds a tree of nodes out of a sequence of tokens. | |||
To use, pass a list of :class:`.Token`\ s to the :meth:`build` method. The | |||
To use, pass a list of :class:`.Token`\\ s to the :meth:`build` method. The | |||
list will be exhausted as it is parsed and a :class:`.Wikicode` object | |||
containing the node tree will be returned. | |||
""" | |||
@@ -237,8 +237,7 @@ class Builder(object): | |||
else: | |||
name, value = self._pop(), None | |||
return Attribute(name, value, quotes, start.pad_first, | |||
start.pad_before_eq, start.pad_after_eq, | |||
check_quotes=False) | |||
start.pad_before_eq, start.pad_after_eq) | |||
else: | |||
self._write(self._handle_token(token)) | |||
raise ParserError("_handle_attribute() missed a close token") | |||
@@ -1,6 +1,6 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
@@ -70,5 +70,5 @@ def parse_anything(value, context=0, skip_style_tags=False): | |||
nodelist += parse_anything(item, context, skip_style_tags).nodes | |||
return Wikicode(nodelist) | |||
except TypeError: | |||
error = "Needs string, Node, Wikicode, int, None, or iterable of these, but got {0}: {1}" | |||
error = "Needs string, Node, Wikicode, file, int, None, or iterable of these, but got {0}: {1}" | |||
raise ValueError(error.format(type(value).__name__, value)) |
@@ -1,6 +1,6 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
@@ -67,7 +67,7 @@ class TreeEqualityTestCase(TestCase): | |||
def assertCommentNodeEqual(self, expected, actual): | |||
"""Assert that two Comment nodes have the same data.""" | |||
self.assertWikicodeEqual(expected.contents, actual.contents) | |||
self.assertEqual(expected.contents, actual.contents) | |||
def assertHeadingNodeEqual(self, expected, actual): | |||
"""Assert that two Heading nodes have the same data.""" | |||
@@ -1,6 +1,6 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
@@ -1,6 +1,6 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
@@ -232,11 +232,11 @@ class TestBuilder(TreeEqualityTestCase): | |||
tests = [ | |||
([tokens.CommentStart(), tokens.Text(text="foobar"), | |||
tokens.CommentEnd()], | |||
wrap([Comment(wraptext("foobar"))])), | |||
wrap([Comment("foobar")])), | |||
([tokens.CommentStart(), tokens.Text(text="spam"), | |||
tokens.Text(text="eggs"), tokens.CommentEnd()], | |||
wrap([Comment(wraptext("spam", "eggs"))])), | |||
wrap([Comment("spameggs")])), | |||
] | |||
for test, valid in tests: | |||
self.assertWikicodeEqual(valid, self.builder.build(test)) | |||
@@ -412,7 +412,7 @@ class TestBuilder(TreeEqualityTestCase): | |||
wraptext("c"), params=[Parameter(wraptext("1"), wrap([Wikilink( | |||
wraptext("d")), Argument(wraptext("e"))]), showkey=False)])]), | |||
showkey=False)]), Wikilink(wraptext("f"), wrap([Argument(wraptext( | |||
"g")), Comment(wraptext("h"))])), Template(wraptext("i"), params=[ | |||
"g")), Comment("h")])), Template(wraptext("i"), params=[ | |||
Parameter(wraptext("j"), wrap([HTMLEntity("nbsp", | |||
named=True)]))])]) | |||
self.assertWikicodeEqual(valid, self.builder.build(test)) | |||