[Python-modules-commits] [python-cssselect] 01/06: New upstream version 1.0.3
Takaki Taniguchi
takaki at moszumanska.debian.org
Sun Feb 4 02:22:00 UTC 2018
This is an automated email from the git hooks/post-receive script.
takaki pushed a commit to branch master
in repository python-cssselect.
commit dd112abaa6e17ae529a3e833b03b685fa32d4380
Author: TANIGUCHI Takaki <takaki at asis.media-as.org>
Date: Sat Feb 3 18:50:34 2018 +0900
New upstream version 1.0.3
---
.bumpversion.cfg | 7 -
.gitignore | 7 -
.travis.yml | 29 -
CHANGES | 16 +
PKG-INFO | 62 ++
README.rst | 20 +-
cssselect.egg-info/PKG-INFO | 62 ++
cssselect.egg-info/SOURCES.txt | 18 +
cssselect.egg-info/dependency_links.txt | 1 +
cssselect.egg-info/top_level.txt | 1 +
cssselect/__init__.py | 2 +-
cssselect/parser.py | 21 +-
cssselect/xpath.py | 4 +-
setup.cfg | 10 +-
setup.py | 3 +-
tests/__init__.py | 0
tests/test_cssselect.py | 1236 -------------------------------
tox.ini | 6 +-
18 files changed, 197 insertions(+), 1308 deletions(-)
diff --git a/.bumpversion.cfg b/.bumpversion.cfg
deleted file mode 100644
index 92c7bcb..0000000
--- a/.bumpversion.cfg
+++ /dev/null
@@ -1,7 +0,0 @@
-[bumpversion]
-current_version = 1.0.1
-commit = True
-tag = True
-
-[bumpversion:file:cssselect/__init__.py]
-
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 4c89f4c..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-*.pyc
-*.egg-info
-/.tox
-/MANIFEST
-/dist
-/docs/_build
-/.coverage
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 5ddb1fd..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-language: python
-python:
- - '2.6'
- - '2.7'
- - '3.3'
- - '3.4'
- - '3.5'
- - '3.6'
-
-install:
- - pip install lxml -e .
- - pip install -U codecov pytest-cov
-
-script:
- py.test --cov-report term --cov=cssselect
-
-after_success:
- codecov
-
-deploy:
- provider: pypi
- distributions: sdist bdist_wheel
- user: redapple
- password:
- secure: T1PBD+ocIGwHMbBHPqzu7UZxpkB0w98KtEIkNzLXNQcF7JpjugZNwz4xX2xVhi8yvUQ257VtLSKpIOT2FWxrfLrgTZKbTd6Q7V5Lf3HKzLomOKUKMAd54gsOuismE27CT/SHbexskACgwVwkyG9Y3dlG6m/ZBgqoPAGaJrScjEU=
- on:
- tags: true
- repo: scrapy/cssselect
- condition: "$TRAVIS_PYTHON_VERSION == '3.6'"
diff --git a/CHANGES b/CHANGES
index 92b0371..0a0e137 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,22 @@
Changelog
=========
+Version 1.0.3
+-------------
+
+Released on 2017-12-27.
+
+* Fix artifact uploads to pypi
+
+Version 1.0.2
+-------------
+
+Released on 2017-12-26.
+
+* Drop support for Python 2.6 and Python 3.3.
+* Fix deprecation warning in Python 3.6.
+* Minor cleanups.
+
Version 1.0.1
-------------
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..9cdd726
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,62 @@
+Metadata-Version: 1.2
+Name: cssselect
+Version: 1.0.3
+Summary: cssselect parses CSS3 Selectors and translates them to XPath 1.0
+Home-page: https://github.com/scrapy/cssselect
+Author: Paul Tremberth
+Author-email: paul.tremberth at gmail.com
+License: BSD
+Description-Content-Type: UNKNOWN
+Description: ===================================
+ cssselect: CSS Selectors for Python
+ ===================================
+
+ .. image:: https://img.shields.io/pypi/v/cssselect.svg
+ :target: https://pypi.python.org/pypi/cssselect
+ :alt: PyPI Version
+
+ .. image:: https://img.shields.io/pypi/pyversions/cssselect.svg
+ :target: https://pypi.python.org/pypi/cssselect
+ :alt: Supported Python Versions
+
+ .. image:: https://img.shields.io/travis/scrapy/cssselect/master.svg
+ :target: https://travis-ci.org/scrapy/cssselect
+ :alt: Build Status
+
+ .. image:: https://img.shields.io/codecov/c/github/scrapy/cssselect/master.svg
+ :target: https://codecov.io/github/scrapy/cssselect?branch=master
+ :alt: Coverage report
+
+ *cssselect* parses `CSS3 Selectors`_ and translate them to `XPath 1.0`_
+ expressions. Such expressions can be used in lxml_ or another XPath engine
+ to find the matching elements in an XML or HTML document.
+
+ This module used to live inside of lxml as ``lxml.cssselect`` before it was
+ extracted as a stand-alone project.
+
+ .. _CSS3 Selectors: https://www.w3.org/TR/css3-selectors/
+ .. _XPath 1.0: https://www.w3.org/TR/xpath/
+ .. _lxml: http://lxml.de/
+
+
+ Quick facts:
+
+ * Free software: BSD licensed
+ * Compatible with Python 2.7 and 3.4+
+ * Latest documentation `on Read the Docs <https://cssselect.readthedocs.io/>`_
+ * Source, issues and pull requests `on GitHub
+ <https://github.com/scrapy/cssselect>`_
+ * Releases `on PyPI <http://pypi.python.org/pypi/cssselect>`_
+ * Install with ``pip install cssselect``
+
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
diff --git a/README.rst b/README.rst
index 587c2d7..9bcd648 100644
--- a/README.rst
+++ b/README.rst
@@ -2,6 +2,22 @@
cssselect: CSS Selectors for Python
===================================
+.. image:: https://img.shields.io/pypi/v/cssselect.svg
+ :target: https://pypi.python.org/pypi/cssselect
+ :alt: PyPI Version
+
+.. image:: https://img.shields.io/pypi/pyversions/cssselect.svg
+ :target: https://pypi.python.org/pypi/cssselect
+ :alt: Supported Python Versions
+
+.. image:: https://img.shields.io/travis/scrapy/cssselect/master.svg
+ :target: https://travis-ci.org/scrapy/cssselect
+ :alt: Build Status
+
+.. image:: https://img.shields.io/codecov/c/github/scrapy/cssselect/master.svg
+ :target: https://codecov.io/github/scrapy/cssselect?branch=master
+ :alt: Coverage report
+
*cssselect* parses `CSS3 Selectors`_ and translate them to `XPath 1.0`_
expressions. Such expressions can be used in lxml_ or another XPath engine
to find the matching elements in an XML or HTML document.
@@ -17,9 +33,9 @@ extracted as a stand-alone project.
Quick facts:
* Free software: BSD licensed
-* Compatible with Python 2.6+ and 3.3+
+* Compatible with Python 2.7 and 3.4+
* Latest documentation `on Read the Docs <https://cssselect.readthedocs.io/>`_
-* Source, issues and pull requests `on Github
+* Source, issues and pull requests `on GitHub
<https://github.com/scrapy/cssselect>`_
* Releases `on PyPI <http://pypi.python.org/pypi/cssselect>`_
* Install with ``pip install cssselect``
diff --git a/cssselect.egg-info/PKG-INFO b/cssselect.egg-info/PKG-INFO
new file mode 100644
index 0000000..9cdd726
--- /dev/null
+++ b/cssselect.egg-info/PKG-INFO
@@ -0,0 +1,62 @@
+Metadata-Version: 1.2
+Name: cssselect
+Version: 1.0.3
+Summary: cssselect parses CSS3 Selectors and translates them to XPath 1.0
+Home-page: https://github.com/scrapy/cssselect
+Author: Paul Tremberth
+Author-email: paul.tremberth at gmail.com
+License: BSD
+Description-Content-Type: UNKNOWN
+Description: ===================================
+ cssselect: CSS Selectors for Python
+ ===================================
+
+ .. image:: https://img.shields.io/pypi/v/cssselect.svg
+ :target: https://pypi.python.org/pypi/cssselect
+ :alt: PyPI Version
+
+ .. image:: https://img.shields.io/pypi/pyversions/cssselect.svg
+ :target: https://pypi.python.org/pypi/cssselect
+ :alt: Supported Python Versions
+
+ .. image:: https://img.shields.io/travis/scrapy/cssselect/master.svg
+ :target: https://travis-ci.org/scrapy/cssselect
+ :alt: Build Status
+
+ .. image:: https://img.shields.io/codecov/c/github/scrapy/cssselect/master.svg
+ :target: https://codecov.io/github/scrapy/cssselect?branch=master
+ :alt: Coverage report
+
+ *cssselect* parses `CSS3 Selectors`_ and translate them to `XPath 1.0`_
+ expressions. Such expressions can be used in lxml_ or another XPath engine
+ to find the matching elements in an XML or HTML document.
+
+ This module used to live inside of lxml as ``lxml.cssselect`` before it was
+ extracted as a stand-alone project.
+
+ .. _CSS3 Selectors: https://www.w3.org/TR/css3-selectors/
+ .. _XPath 1.0: https://www.w3.org/TR/xpath/
+ .. _lxml: http://lxml.de/
+
+
+ Quick facts:
+
+ * Free software: BSD licensed
+ * Compatible with Python 2.7 and 3.4+
+ * Latest documentation `on Read the Docs <https://cssselect.readthedocs.io/>`_
+ * Source, issues and pull requests `on GitHub
+ <https://github.com/scrapy/cssselect>`_
+ * Releases `on PyPI <http://pypi.python.org/pypi/cssselect>`_
+ * Install with ``pip install cssselect``
+
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
diff --git a/cssselect.egg-info/SOURCES.txt b/cssselect.egg-info/SOURCES.txt
new file mode 100644
index 0000000..91a07c6
--- /dev/null
+++ b/cssselect.egg-info/SOURCES.txt
@@ -0,0 +1,18 @@
+.coveragerc
+AUTHORS
+CHANGES
+LICENSE
+MANIFEST.in
+README.rst
+setup.cfg
+setup.py
+tox.ini
+cssselect/__init__.py
+cssselect/parser.py
+cssselect/xpath.py
+cssselect.egg-info/PKG-INFO
+cssselect.egg-info/SOURCES.txt
+cssselect.egg-info/dependency_links.txt
+cssselect.egg-info/top_level.txt
+docs/conf.py
+docs/index.rst
\ No newline at end of file
diff --git a/cssselect.egg-info/dependency_links.txt b/cssselect.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/cssselect.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/cssselect.egg-info/top_level.txt b/cssselect.egg-info/top_level.txt
new file mode 100644
index 0000000..d2a154e
--- /dev/null
+++ b/cssselect.egg-info/top_level.txt
@@ -0,0 +1 @@
+cssselect
diff --git a/cssselect/__init__.py b/cssselect/__init__.py
index 3b06261..e9f9ce1 100644
--- a/cssselect/__init__.py
+++ b/cssselect/__init__.py
@@ -18,5 +18,5 @@ from cssselect.parser import (parse, Selector, FunctionalPseudoElement,
from cssselect.xpath import GenericTranslator, HTMLTranslator, ExpressionError
-VERSION = '1.0.1'
+VERSION = '1.0.3'
__version__ = VERSION
diff --git a/cssselect/parser.py b/cssselect/parser.py
index d155252..9bb039c 100644
--- a/cssselect/parser.py
+++ b/cssselect/parser.py
@@ -358,8 +358,6 @@ def parse(css):
# message = "%s at %s -> %r" % (
# e, stream.used, stream.peek())
# e.msg = message
-# if sys.version_info < (2,6):
-# e.message = message
# e.args = tuple([message])
# raise
@@ -554,14 +552,14 @@ def parse_series(tokens):
raise ValueError('String tokens not allowed in series.')
s = ''.join(token.value for token in tokens).strip()
if s == 'odd':
- return (2, 1)
+ return 2, 1
elif s == 'even':
- return (2, 0)
+ return 2, 0
elif s == 'n':
- return (1, 0)
+ return 1, 0
if 'n' not in s:
# Just b
- return (0, int(s))
+ return 0, int(s)
a, b = s.split('n', 1)
if not a:
a = 1
@@ -573,7 +571,7 @@ def parse_series(tokens):
b = 0
else:
b = int(b)
- return (a, b)
+ return a, b
#### Token objects
@@ -617,7 +615,7 @@ def _compile(pattern):
return re.compile(pattern % vars(TokenMacros), re.IGNORECASE).match
_match_whitespace = _compile(r'[ \t\r\n\f]+')
-_match_number = _compile('[+-]?(?:[0-9]*\.[0-9]+|[0-9]+)')
+_match_number = _compile(r'[+-]?(?:[0-9]*\.[0-9]+|[0-9]+)')
_match_hash = _compile('#(?:%(nmchar)s)+')
_match_ident = _compile('-?(?:%(nmstart)s)(?:%(nmchar)s)*')
_match_string_by_quote = {
@@ -630,12 +628,7 @@ _sub_unicode_escape = re.compile(TokenMacros.unicode_escape, re.I).sub
_sub_newline_escape =re.compile(r'\\(?:\n|\r\n|\r|\f)').sub
# Same as r'\1', but faster on CPython
-if hasattr(operator, 'methodcaller'):
- # Python 2.6+
- _replace_simple = operator.methodcaller('group', 1)
-else:
- def _replace_simple(match):
- return match.group(1)
+_replace_simple = operator.methodcaller('group', 1)
def _replace_unicode(match):
codepoint = int(match.group(1), 16)
diff --git a/cssselect/xpath.py b/cssselect/xpath.py
index 698748a..22cd029 100644
--- a/cssselect/xpath.py
+++ b/cssselect/xpath.py
@@ -114,7 +114,7 @@ class GenericTranslator(object):
####
#### You are welcome to hook into this to change some behavior,
#### but do so at your own risks.
- #### Until is has recieved a lot more work and review,
+ #### Until it has received a lot more work and review,
#### I reserve the right to change this API in backward-incompatible ways
#### with any minor version of cssselect.
#### See https://github.com/scrapy/cssselect/pull/22
@@ -490,7 +490,7 @@ class GenericTranslator(object):
b_neg = (-b_min_1) % abs(a)
if b_neg != 0:
- b_neg = '+%s' % (b_neg)
+ b_neg = '+%s' % b_neg
left = '(%s %s)' % (left, b_neg)
expr.append('%s mod %s = 0' % (left, a))
diff --git a/setup.cfg b/setup.cfg
index b8c93b1..57caa3e 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,9 +1,8 @@
[build_sphinx]
source-dir = docs
-build-dir = docs/_build
-#all_files = 1
+build-dir = docs/_build
-[upload_sphinx] # Sphinx-PyPI-upload
+[upload_sphinx]
upload-dir = docs/_build/html
[tool:pytest]
@@ -11,3 +10,8 @@ testpaths = tests
[bdist_wheel]
universal = 1
+
+[egg_info]
+tag_build =
+tag_date = 0
+
diff --git a/setup.py b/setup.py
index 199ffc7..243927d 100644
--- a/setup.py
+++ b/setup.py
@@ -29,15 +29,14 @@ setup(
url='https://github.com/scrapy/cssselect',
license='BSD',
packages=['cssselect'],
+ python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
classifiers=[
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
diff --git a/tests/__init__.py b/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/test_cssselect.py b/tests/test_cssselect.py
deleted file mode 100644
index 4a0bd39..0000000
--- a/tests/test_cssselect.py
+++ /dev/null
@@ -1,1236 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-"""
- Tests for cssselect
- ===================
-
- These tests can be run either by py.test or by the standard library's
- unittest. They use plain ``assert`` statements and do little reporting
- themselves in case of failure.
-
- Use py.test to get fancy error reporting and assert introspection.
-
-
- :copyright: (c) 2007-2012 Ian Bicking and contributors.
- See AUTHORS for more details.
- :license: BSD, see LICENSE for more details.
-
-"""
-
-import sys
-import unittest
-
-from lxml import etree, html
-from cssselect import (parse, GenericTranslator, HTMLTranslator,
- SelectorSyntaxError, ExpressionError)
-from cssselect.parser import (tokenize, parse_series, _unicode,
- FunctionalPseudoElement)
-from cssselect.xpath import _unicode_safe_getattr, XPathExpr
-
-
-if sys.version_info[0] < 3:
- # Python 2
- def u(text):
- return text.decode('utf8')
-else:
- # Python 3
- def u(text):
- return text
-
-
-class TestCssselect(unittest.TestCase):
- def test_tokenizer(self):
- tokens = [
- _unicode(item) for item in tokenize(
- u(r'E\ é > f [a~="y\"x"]:nth(/* fu /]* */-3.7)'))]
- assert tokens == [
- u("<IDENT 'E é' at 0>"),
- "<S ' ' at 4>",
- "<DELIM '>' at 5>",
- "<S ' ' at 6>",
- # the no-break space is not whitespace in CSS
- u("<IDENT 'f ' at 7>"), # f\xa0
- "<DELIM '[' at 9>",
- "<IDENT 'a' at 10>",
- "<DELIM '~' at 11>",
- "<DELIM '=' at 12>",
- "<STRING 'y\"x' at 13>",
- "<DELIM ']' at 19>",
- "<DELIM ':' at 20>",
- "<IDENT 'nth' at 21>",
- "<DELIM '(' at 24>",
- "<NUMBER '-3.7' at 37>",
- "<DELIM ')' at 41>",
- "<EOF at 42>",
- ]
-
- def test_parser(self):
- def repr_parse(css):
- selectors = parse(css)
- for selector in selectors:
- assert selector.pseudo_element is None
- return [repr(selector.parsed_tree).replace("(u'", "('")
- for selector in selectors]
-
- def parse_many(first, *others):
- result = repr_parse(first)
- for other in others:
- assert repr_parse(other) == result
- return result
-
- assert parse_many('*') == ['Element[*]']
- assert parse_many('*|*') == ['Element[*]']
- assert parse_many('*|foo') == ['Element[foo]']
- assert parse_many('foo|*') == ['Element[foo|*]']
- assert parse_many('foo|bar') == ['Element[foo|bar]']
- # This will never match, but it is valid:
- assert parse_many('#foo#bar') == ['Hash[Hash[Element[*]#foo]#bar]']
- assert parse_many(
- 'div>.foo',
- 'div> .foo',
- 'div >.foo',
- 'div > .foo',
- 'div \n> \t \t .foo', 'div\r>\n\n\n.foo', 'div\f>\f.foo'
- ) == ['CombinedSelector[Element[div] > Class[Element[*].foo]]']
- assert parse_many('td.foo,.bar',
- 'td.foo, .bar',
- 'td.foo\t\r\n\f ,\t\r\n\f .bar'
- ) == [
- 'Class[Element[td].foo]',
- 'Class[Element[*].bar]'
- ]
- assert parse_many('div, td.foo, div.bar span') == [
- 'Element[div]',
- 'Class[Element[td].foo]',
- 'CombinedSelector[Class[Element[div].bar] '
- '<followed> Element[span]]']
- assert parse_many('div > p') == [
- 'CombinedSelector[Element[div] > Element[p]]']
- assert parse_many('td:first') == [
- 'Pseudo[Element[td]:first]']
- assert parse_many('td:first') == [
- 'Pseudo[Element[td]:first]']
- assert parse_many('td :first') == [
- 'CombinedSelector[Element[td] '
- '<followed> Pseudo[Element[*]:first]]']
- assert parse_many('td :first') == [
- 'CombinedSelector[Element[td] '
- '<followed> Pseudo[Element[*]:first]]']
- assert parse_many('a[name]', 'a[ name\t]') == [
- 'Attrib[Element[a][name]]']
- assert parse_many('a [name]') == [
- 'CombinedSelector[Element[a] <followed> Attrib[Element[*][name]]]']
- assert parse_many('a[rel="include"]', 'a[rel = include]') == [
- "Attrib[Element[a][rel = 'include']]"]
- assert parse_many("a[hreflang |= 'en']", "a[hreflang|=en]") == [
- "Attrib[Element[a][hreflang |= 'en']]"]
- assert parse_many('div:nth-child(10)') == [
- "Function[Element[div]:nth-child(['10'])]"]
- assert parse_many(':nth-child(2n+2)') == [
- "Function[Element[*]:nth-child(['2', 'n', '+2'])]"]
- assert parse_many('div:nth-of-type(10)') == [
- "Function[Element[div]:nth-of-type(['10'])]"]
- assert parse_many('div div:nth-of-type(10) .aclass') == [
- 'CombinedSelector[CombinedSelector[Element[div] <followed> '
- "Function[Element[div]:nth-of-type(['10'])]] "
- '<followed> Class[Element[*].aclass]]']
- assert parse_many('label:only') == [
- 'Pseudo[Element[label]:only]']
- assert parse_many('a:lang(fr)') == [
- "Function[Element[a]:lang(['fr'])]"]
- assert parse_many('div:contains("foo")') == [
- "Function[Element[div]:contains(['foo'])]"]
- assert parse_many('div#foobar') == [
- 'Hash[Element[div]#foobar]']
- assert parse_many('div:not(div.foo)') == [
- 'Negation[Element[div]:not(Class[Element[div].foo])]']
- assert parse_many('td ~ th') == [
- 'CombinedSelector[Element[td] ~ Element[th]]']
-
- def test_pseudo_elements(self):
- def parse_pseudo(css):
- result = []
- for selector in parse(css):
- pseudo = selector.pseudo_element
- pseudo = _unicode(pseudo) if pseudo else pseudo
- # No Symbol here
- assert pseudo is None or type(pseudo) is _unicode
- selector = repr(selector.parsed_tree).replace("(u'", "('")
- result.append((selector, pseudo))
- return result
-
- def parse_one(css):
- result = parse_pseudo(css)
- assert len(result) == 1
- return result[0]
-
- assert parse_one('foo') == ('Element[foo]', None)
- assert parse_one('*') == ('Element[*]', None)
- assert parse_one(':empty') == ('Pseudo[Element[*]:empty]', None)
-
- # Special cases for CSS 2.1 pseudo-elements
- assert parse_one(':BEfore') == ('Element[*]', 'before')
- assert parse_one(':aftER') == ('Element[*]', 'after')
- assert parse_one(':First-Line') == ('Element[*]', 'first-line')
- assert parse_one(':First-Letter') == ('Element[*]', 'first-letter')
-
- assert parse_one('::befoRE') == ('Element[*]', 'before')
- assert parse_one('::AFter') == ('Element[*]', 'after')
- assert parse_one('::firsT-linE') == ('Element[*]', 'first-line')
- assert parse_one('::firsT-letteR') == ('Element[*]', 'first-letter')
-
- assert parse_one('::text-content') == ('Element[*]', 'text-content')
- assert parse_one('::attr(name)') == (
- "Element[*]", "FunctionalPseudoElement[::attr(['name'])]")
-
- assert parse_one('::Selection') == ('Element[*]', 'selection')
- assert parse_one('foo:after') == ('Element[foo]', 'after')
- assert parse_one('foo::selection') == ('Element[foo]', 'selection')
- assert parse_one('lorem#ipsum ~ a#b.c[href]:empty::selection') == (
- 'CombinedSelector[Hash[Element[lorem]#ipsum] ~ '
- 'Pseudo[Attrib[Class[Hash[Element[a]#b].c][href]]:empty]]',
- 'selection')
-
- parse_pseudo('foo:before, bar, baz:after') == [
- ('Element[foo]', 'before'),
- ('Element[bar]', None),
- ('Element[baz]', 'after')]
-
- # Special cases for CSS 2.1 pseudo-elements are ignored by default
- for pseudo in ('after', 'before', 'first-line', 'first-letter'):
- selector, = parse('e:%s' % pseudo)
- assert selector.pseudo_element == pseudo
- assert GenericTranslator().selector_to_xpath(selector, prefix='') == "e"
-
- # Pseudo Elements are ignored by default, but if allowed they are not
- # supported by GenericTranslator
- tr = GenericTranslator()
- selector, = parse('e::foo')
- assert selector.pseudo_element == 'foo'
- assert tr.selector_to_xpath(selector, prefix='') == "e"
- self.assertRaises(ExpressionError, tr.selector_to_xpath, selector,
- translate_pseudo_elements=True)
-
- def test_specificity(self):
- def specificity(css):
- selectors = parse(css)
- assert len(selectors) == 1
- return selectors[0].specificity()
-
- assert specificity('*') == (0, 0, 0)
- assert specificity(' foo') == (0, 0, 1)
- assert specificity(':empty ') == (0, 1, 0)
- assert specificity(':before') == (0, 0, 1)
- assert specificity('*:before') == (0, 0, 1)
- assert specificity(':nth-child(2)') == (0, 1, 0)
- assert specificity('.bar') == (0, 1, 0)
- assert specificity('[baz]') == (0, 1, 0)
- assert specificity('[baz="4"]') == (0, 1, 0)
- assert specificity('[baz^="4"]') == (0, 1, 0)
- assert specificity('#lipsum') == (1, 0, 0)
-
- assert specificity(':not(*)') == (0, 0, 0)
- assert specificity(':not(foo)') == (0, 0, 1)
- assert specificity(':not(.foo)') == (0, 1, 0)
- assert specificity(':not([foo])') == (0, 1, 0)
- assert specificity(':not(:empty)') == (0, 1, 0)
- assert specificity(':not(#foo)') == (1, 0, 0)
-
- assert specificity('foo:empty') == (0, 1, 1)
- assert specificity('foo:before') == (0, 0, 2)
- assert specificity('foo::before') == (0, 0, 2)
- assert specificity('foo:empty::before') == (0, 1, 2)
-
- assert specificity('#lorem + foo#ipsum:first-child > bar:first-line'
- ) == (2, 1, 3)
-
- def test_parse_errors(self):
- def get_error(css):
- try:
- parse(css)
- except SelectorSyntaxError:
- # Py2, Py3, ...
- return str(sys.exc_info()[1]).replace("(u'", "('")
-
- assert get_error('attributes(href)/html/body/a') == (
- "Expected selector, got <DELIM '(' at 10>")
- assert get_error('attributes(href)') == (
- "Expected selector, got <DELIM '(' at 10>")
- assert get_error('html/body/a') == (
- "Expected selector, got <DELIM '/' at 4>")
- assert get_error(' ') == (
- "Expected selector, got <EOF at 1>")
- assert get_error('div, ') == (
- "Expected selector, got <EOF at 5>")
- assert get_error(' , div') == (
- "Expected selector, got <DELIM ',' at 1>")
- assert get_error('p, , div') == (
- "Expected selector, got <DELIM ',' at 3>")
- assert get_error('div > ') == (
- "Expected selector, got <EOF at 6>")
- assert get_error(' > div') == (
- "Expected selector, got <DELIM '>' at 2>")
- assert get_error('foo|#bar') == (
- "Expected ident or '*', got <HASH 'bar' at 4>")
- assert get_error('#.foo') == (
- "Expected selector, got <DELIM '#' at 0>")
- assert get_error('.#foo') == (
- "Expected ident, got <HASH 'foo' at 1>")
- assert get_error(':#foo') == (
- "Expected ident, got <HASH 'foo' at 1>")
- assert get_error('[*]') == (
- "Expected '|', got <DELIM ']' at 2>")
- assert get_error('[foo|]') == (
- "Expected ident, got <DELIM ']' at 5>")
- assert get_error('[#]') == (
- "Expected ident or '*', got <DELIM '#' at 1>")
- assert get_error('[foo=#]') == (
- "Expected string or ident, got <DELIM '#' at 5>")
- assert get_error('[href]a') == (
- "Expected selector, got <IDENT 'a' at 6>")
- assert get_error('[rel=stylesheet]') == None
- assert get_error('[rel:stylesheet]') == (
- "Operator expected, got <DELIM ':' at 4>")
- assert get_error('[rel=stylesheet') == (
- "Expected ']', got <EOF at 15>")
- assert get_error(':lang(fr)') == None
- assert get_error(':lang(fr') == (
- "Expected an argument, got <EOF at 8>")
- assert get_error(':contains("foo') == (
- "Unclosed string at 10")
- assert get_error('foo!') == (
- "Expected selector, got <DELIM '!' at 3>")
-
- # Mis-placed pseudo-elements
- assert get_error('a:before:empty') == (
- "Got pseudo-element ::before not at the end of a selector")
- assert get_error('li:before a') == (
- "Got pseudo-element ::before not at the end of a selector")
- assert get_error(':not(:before)') == (
- "Got pseudo-element ::before inside :not() at 12")
- assert get_error(':not(:not(a))') == (
- "Got nested :not()")
-
- def test_translation(self):
- def xpath(css):
- return _unicode(GenericTranslator().css_to_xpath(css, prefix=''))
-
- assert xpath('*') == "*"
- assert xpath('e') == "e"
- assert xpath('*|e') == "e"
- assert xpath('e|f') == "e:f"
- assert xpath('e[foo]') == "e[@foo]"
- assert xpath('e[foo|bar]') == "e[@foo:bar]"
- assert xpath('e[foo="bar"]') == "e[@foo = 'bar']"
- assert xpath('e[foo~="bar"]') == (
- "e[@foo and contains("
- "concat(' ', normalize-space(@foo), ' '), ' bar ')]")
- assert xpath('e[foo^="bar"]') == (
- "e[@foo and starts-with(@foo, 'bar')]")
- assert xpath('e[foo$="bar"]') == (
- "e[@foo and substring(@foo, string-length(@foo)-2) = 'bar']")
- assert xpath('e[foo*="bar"]') == (
- "e[@foo and contains(@foo, 'bar')]")
- assert xpath('e[hreflang|="en"]') == (
- "e[@hreflang and ("
- "@hreflang = 'en' or starts-with(@hreflang, 'en-'))]")
-
- # --- nth-* and nth-last-* -------------------------------------
- assert xpath('e:nth-child(1)') == (
- "e[count(preceding-sibling::*) = 0]")
-
- # always true
- assert xpath('e:nth-child(n)') == (
- "e")
- assert xpath('e:nth-child(n+1)') == (
- "e")
- # always true too
- assert xpath('e:nth-child(n-10)') == (
- "e")
- # b=2 is the limit...
- assert xpath('e:nth-child(n+2)') == (
- "e[count(preceding-sibling::*) >= 1]")
- # always false
- assert xpath('e:nth-child(-n)') == (
- "e[0]")
- # equivalent to first child
- assert xpath('e:nth-child(-n+1)') == (
- "e[count(preceding-sibling::*) <= 0]")
-
- assert xpath('e:nth-child(3n+2)') == (
- "e[count(preceding-sibling::*) >= 1 and "
- "(count(preceding-sibling::*) +2) mod 3 = 0]")
- assert xpath('e:nth-child(3n-2)') == (
- "e[count(preceding-sibling::*) mod 3 = 0]")
- assert xpath('e:nth-child(-n+6)') == (
- "e[count(preceding-sibling::*) <= 5]")
-
- assert xpath('e:nth-last-child(1)') == (
- "e[count(following-sibling::*) = 0]")
- assert xpath('e:nth-last-child(2n)') == (
- "e[(count(following-sibling::*) +1) mod 2 = 0]")
- assert xpath('e:nth-last-child(2n+1)') == (
- "e[count(following-sibling::*) mod 2 = 0]")
- assert xpath('e:nth-last-child(2n+2)') == (
- "e[count(following-sibling::*) >= 1 and "
- "(count(following-sibling::*) +1) mod 2 = 0]")
- assert xpath('e:nth-last-child(3n+1)') == (
- "e[count(following-sibling::*) mod 3 = 0]")
- # represents the two last e elements
- assert xpath('e:nth-last-child(-n+2)') == (
- "e[count(following-sibling::*) <= 1]")
-
- assert xpath('e:nth-of-type(1)') == (
- "e[count(preceding-sibling::e) = 0]")
- assert xpath('e:nth-last-of-type(1)') == (
- "e[count(following-sibling::e) = 0]")
- assert xpath('div e:nth-last-of-type(1) .aclass') == (
- "div/descendant-or-self::*/e[count(following-sibling::e) = 0]"
- "/descendant-or-self::*/*[@class and contains("
- "concat(' ', normalize-space(@class), ' '), ' aclass ')]")
-
- assert xpath('e:first-child') == (
- "e[count(preceding-sibling::*) = 0]")
- assert xpath('e:last-child') == (
- "e[count(following-sibling::*) = 0]")
- assert xpath('e:first-of-type') == (
- "e[count(preceding-sibling::e) = 0]")
- assert xpath('e:last-of-type') == (
- "e[count(following-sibling::e) = 0]")
- assert xpath('e:only-child') == (
- "e[count(parent::*/child::*) = 1]")
- assert xpath('e:only-of-type') == (
- "e[count(parent::*/child::e) = 1]")
- assert xpath('e:empty') == (
- "e[not(*) and not(string-length())]")
- assert xpath('e:EmPTY') == (
- "e[not(*) and not(string-length())]")
- assert xpath('e:root') == (
- "e[not(parent::*)]")
- assert xpath('e:hover') == (
- "e[0]") # never matches
- assert xpath('e:contains("foo")') == (
- "e[contains(., 'foo')]")
- assert xpath('e:ConTains(foo)') == (
- "e[contains(., 'foo')]")
- assert xpath('e.warning') == (
- "e[@class and contains("
- "concat(' ', normalize-space(@class), ' '), ' warning ')]")
- assert xpath('e#myid') == (
- "e[@id = 'myid']")
- assert xpath('e:not(:nth-child(odd))') == (
- "e[not(count(preceding-sibling::*) mod 2 = 0)]")
- assert xpath('e:nOT(*)') == (
- "e[0]") # never matches
- assert xpath('e f') == (
- "e/descendant-or-self::*/f")
- assert xpath('e > f') == (
- "e/f")
- assert xpath('e + f') == (
- "e/following-sibling::*[name() = 'f' and (position() = 1)]")
- assert xpath('e ~ f') == (
- "e/following-sibling::f")
- assert xpath('e ~ f:nth-child(3)') == (
- "e/following-sibling::f[count(preceding-sibling::*) = 2]")
- assert xpath('div#container p') == (
- "div[@id = 'container']/descendant-or-self::*/p")
-
- # Invalid characters in XPath element names
- assert xpath(r'di\a0 v') == (
- u("*[name() = 'di v']")) # di\xa0v
- assert xpath(r'di\[v') == (
- "*[name() = 'di[v']")
- assert xpath(r'[h\a0 ref]') == (
- u("*[attribute::*[name() = 'h ref']]")) # h\xa0ref
- assert xpath(r'[h\]ref]') == (
- "*[attribute::*[name() = 'h]ref']]")
-
- self.assertRaises(ExpressionError, xpath, u(':fİrst-child'))
- self.assertRaises(ExpressionError, xpath, ':first-of-type')
- self.assertRaises(ExpressionError, xpath, ':only-of-type')
- self.assertRaises(ExpressionError, xpath, ':last-of-type')
- self.assertRaises(ExpressionError, xpath, ':nth-of-type(1)')
- self.assertRaises(ExpressionError, xpath, ':nth-last-of-type(1)')
- self.assertRaises(ExpressionError, xpath, ':nth-child(n-)')
- self.assertRaises(ExpressionError, xpath, ':after')
- self.assertRaises(ExpressionError, xpath, ':lorem-ipsum')
- self.assertRaises(ExpressionError, xpath, ':lorem(ipsum)')
- self.assertRaises(ExpressionError, xpath, '::lorem-ipsum')
- self.assertRaises(TypeError, GenericTranslator().css_to_xpath, 4)
- self.assertRaises(TypeError, GenericTranslator().selector_to_xpath,
- 'foo')
-
- def test_unicode(self):
- if sys.version_info[0] < 3:
- css = '.a\xc1b'.decode('ISO-8859-1')
- else:
- css = '.a\xc1b'
-
- xpath = GenericTranslator().css_to_xpath(css)
- assert css[1:] in xpath
- xpath = xpath.encode('ascii', 'xmlcharrefreplace').decode('ASCII')
- assert xpath == (
- "descendant-or-self::*[@class and contains("
- "concat(' ', normalize-space(@class), ' '), ' aÁb ')]")
-
- def test_quoting(self):
- css_to_xpath = GenericTranslator().css_to_xpath
- assert css_to_xpath('*[aval="\'"]') == (
- '''descendant-or-self::*[@aval = "'"]''')
- assert css_to_xpath('*[aval="\'\'\'"]') == (
- """descendant-or-self::*[@aval = "'''"]""")
- assert css_to_xpath('*[aval=\'"\']') == (
- '''descendant-or-self::*[@aval = '"']''')
- assert css_to_xpath('*[aval=\'"""\']') == (
- '''descendant-or-self::*[@aval = '"""']''')
-
- def test_unicode_escapes(self):
- # \22 == '"' \20 == ' '
- css_to_xpath = GenericTranslator().css_to_xpath
- assert css_to_xpath(r'*[aval="\'\22\'"]') == (
- '''descendant-or-self::*[@aval = concat("'",'"',"'")]''')
- assert css_to_xpath(r'*[aval="\'\22 2\'"]') == (
- '''descendant-or-self::*[@aval = concat("'",'"2',"'")]''')
- assert css_to_xpath(r'*[aval="\'\20 \'"]') == (
- '''descendant-or-self::*[@aval = "' '"]''')
- assert css_to_xpath('*[aval="\'\\20\r\n \'"]') == (
- '''descendant-or-self::*[@aval = "' '"]''')
-
- def test_xpath_pseudo_elements(self):
- class CustomTranslator(GenericTranslator):
- def xpath_pseudo_element(self, xpath, pseudo_element):
- if isinstance(pseudo_element, FunctionalPseudoElement):
- method = 'xpath_%s_functional_pseudo_element' % (
- pseudo_element.name.replace('-', '_'))
- method = _unicode_safe_getattr(self, method, None)
- if not method:
- raise ExpressionError(
- "The functional pseudo-element ::%s() is unknown"
- % pseudo_element.name)
- xpath = method(xpath, pseudo_element.arguments)
- else:
- method = 'xpath_%s_simple_pseudo_element' % (
- pseudo_element.replace('-', '_'))
- method = _unicode_safe_getattr(self, method, None)
- if not method:
- raise ExpressionError(
- "The pseudo-element ::%s is unknown"
- % pseudo_element)
- xpath = method(xpath)
- return xpath
... 735 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-cssselect.git
More information about the Python-modules-commits
mailing list