Permalink
Browse files

Fix some cases for the parsing of series (see #7)

  • Loading branch information...
1 parent 5bc7090 commit ab9992212b9620de03028afe29e404852bad42b3 @SimonSapin SimonSapin committed Apr 20, 2012
Showing with 29 additions and 18 deletions.
  1. +12 −16 cssselect/parser.py
  2. +13 −1 cssselect/tests.py
  3. +4 −1 cssselect/xpath.py
View
@@ -356,10 +356,11 @@ def parse_simple_selector(stream, inside_negation=False):
stream.next()
result = parse_attrib(result, stream)
next = stream.next()
- if next != ']':
+ if next == ']':
+ continue
+ else:
raise SelectorSyntaxError(
"Expected ']', got '%s'" % next)
- continue
elif peek == '::':
stream.next()
pseudo_element = stream.next_symbol()
@@ -396,10 +397,11 @@ def parse_simple_selector(stream, inside_negation=False):
result = Function(result, ident, argument)
stream.skip_whitespace()
next = stream.next()
- if not next == ')':
+ if next == ')':
+ continue
+ else:
raise SelectorSyntaxError(
"Expected ')', got '%s'" % next)
- continue
else:
raise SelectorSyntaxError(
"Expected selector, got '%s'" % peek)
@@ -439,24 +441,20 @@ def parse_attrib(selector, stream):
def parse_series(s):
"""
- Parses things like '1n+2', or 'an+b' generally, returning (a, b)
+ Parses things like '1n+2', or 'an+b' generally
+
+ :raises: :class:`ValueError`
+ :returns: :``(a, b)``
+
"""
- if isinstance(s, Element):
- s = s._format_element()
- if not s or s == '*':
- # Happens when there's nothing, which the CSS parser thinks of as *
- return (0, 0)
- if isinstance(s, int):
- # Happens when you just get a number
- return (0, s)
if s == 'odd':
return (2, 1)
elif s == 'even':
return (2, 0)
elif s == 'n':
return (1, 0)
if 'n' not in s:
- # Just a b
+ # Just b
return (0, int(s))
a, b = s.split('n', 1)
if not a:
@@ -467,8 +465,6 @@ def parse_series(s):
a = int(a)
if not b:
b = 0
- elif b == '-' or b == '+':
- b = int(b+'1')
else:
b = int(b)
return (a, b)
View
@@ -271,9 +271,16 @@ def get_error(css):
"[Token('[', 0), Symbol('href', 1), Token(']', 5)]"
" -> Symbol('a', 6)")
assert get_error('[rel=stylesheet]') == None
+ assert get_error('[rel:stylesheet]') == (
+ "Operator expected, got ':' at [Token('[', 0), Symbol('rel', 1), "
+ "Token(':', 4)] -> Symbol('stylesheet', 5)")
assert get_error('[rel=stylesheet') == (
"Expected ']', got 'None' at [Token('[', 0), Symbol('rel', 1), "
"Token('=', 4), Symbol('stylesheet', 5)] -> None")
+ assert get_error(':lang(fr)') == None
+ assert get_error(':lang(fr') == (
+ "Expected ')', got 'None' at [Token(':', 0), Symbol('lang', 1), "
+ "Token('(', 5), Symbol('fr', 6)] -> None")
# Mis-placed pseudo-elements
assert get_error('a:before:empty') == (
@@ -372,7 +379,10 @@ def xpath(css):
"e/following-sibling::f")
assert xpath('div#container p') == (
"div[@id = 'container']/descendant-or-self::*/p")
- self.assertRaises(ExpressionError, xpath, 'p *:only-of-type')
+ self.assertRaises(ExpressionError, xpath, 'p :only-of-type')
+ self.assertRaises(ExpressionError, xpath, ':lang(fr)')
+ self.assertRaises(ExpressionError, xpath, ':nth-child(n-)')
+
def test_unicode(self):
if sys.version_info[0] >= 3:
@@ -417,6 +427,8 @@ def test_series(self):
assert parse_series('even') == (2, 0)
assert parse_series('3n') == (3, 0)
assert parse_series('n') == (1, 0)
+ assert parse_series('+n') == (1, 0)
+ assert parse_series('-n') == (-1, 0)
assert parse_series('5') == (0, 5)
def test_select(self):
View
@@ -315,7 +315,10 @@ def xpath_indirect_adjacent_combinator(self, left, right):
def xpath_nth_child_function(self, xpath, function, last=False,
add_name_test=True):
- a, b = parse_series(function.arguments)
+ try:
+ a, b = parse_series(function.arguments)
+ except ValueError:
+ raise ExpressionError("Invalid series: '%r'" % function.arguments)
if not a and not b and not last:
# a=0 means nothing is returned...
return xpath.add_condition('false() and position() = 0')

0 comments on commit ab99922

Please sign in to comment.