NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #800 most downloaded on PyPI
cssselect parses CSS3 Selectors and translates them to XPath 1.0
Last release 2 months ago
27 Jul 2026
Release timing varies
gaps range from 3 months to 3.2 years
Nearly every release is documented
notes for 21 of 22 stable releases
Nothing withdrawn
no release was ever pulled
14 years old
22 releases · first in 2012
Bump version: 1.4.0 → 1.5.0
Bump version: 1.4.0 → 1.5.0
Released on 2026-07-27.
Backward-incompatible change: removed the no longer used
closing_combiner and has_inner_condition arguments of
XPathExpr.join(). They were added for :has() support which no
longer needs them.
Fixed and improved support for the following selector features:
:has() pseudo-class.
:is(), :where() and :matches() pseudo-classes.
:scope pseudo-class.
:only-child and :only-of-type pseudo-classes.
Namespaces (|).
An+B arguments of pseudo-classes.
Type selectors in predicates.
Fixed some issues with the Selector.canonical() method.
Improved the Element.__repr__() and Relation.__repr__() methods.
Fixed Selector.specificity() calculation for the :is(),
:where() and :matches() pseudo-classes.
Fixed issues with whitespace and comment handling inside some selectors.
Fixed some exception types and messages.
Improved the docs about the :has(), :is() and :where()
pseudo-classes and the `!=`` attribute operator.
Test improvements.
One column per quarter.
Bump version: 1.3.0 → 1.4.0
Bump version: 1.3.0 → 1.4.0
Released on 2026-01-29.
Dropped support for Python 3.9 and PyPy 3.10.
Added support for Python 3.14 and PyPy 3.11.
Switched the build system to hatchling.
CI fixes and improvements.
Bump version: 1.2.0 → 1.3.0
Bump version: 1.2.0 → 1.3.0
Released on 2025-03-10.
Dropped support for Python 3.7-3.8, added support for Python 3.12-3.13 and PyPy 3.10.
Removed _unicode_safe_getattr(), deprecated in 1.2.0.
Added pre-commit and formatted the code with ruff.
Many CI additions and improvements.
Bump version: 1.1.0 → 1.2.0
Bump version: 1.1.0 → 1.2.0
Released on 2022-10-27.
Drop support for Python 2.7, 3.4-3.6, add support for Python 3.7-3.11.
Add type annotations (PEP 484 and PEP 561).
More features from the CSS Selectors Level 4:
The :is() pseudo-class.
The :where() pseudo-class.
The :has() pseudo-class, with some limitations.
Fix parsing :scope after a comma.
Add parentheses to fix condition precedence in some cases.
Private API changes related to the removal of the Python 2 support:
Remove _unicode and _unichr aliases from csselect.parser.
Remove _basestring and _unicode aliases from csselect.xpath.
Deprecate csselect.xpath._unicode_safe_getattr() and change it to just
call getattr().
Include tests in the PyPI tarball.
Many CI additions and improvements.
Improve the test coverage.
Bump version: 1.0.3 → 1.1.0
Bump version: 1.0.3 → 1.1.0
Released on 2019-08-09.
Support for the :scope selector, which allows to access immediate
children of a selector.
Support for the |E syntax for type selectors without a namespace.
A new selector method, canonical, returns the CSS expression of the
selector, as a string.
Bump version: 1.0.2 → 1.0.3
Bump version: 1.0.2 → 1.0.3
Bump version: 1.0.0 → 1.0.1
Bump version: 1.0.0 → 1.0.1
Released on 2017-01-10.
on Read the Docs <https://cssselect.readthedocs.io/>_Bump version: 0.9.2 → 1.0.0
Bump version: 0.9.2 → 1.0.0
Released on 2016-10-21.
:nth-*(an+b) pseudo-classes selectors.
(except *:nth-child() which looks untranslatable to XPath 1.0.)Bump version: 0.9.1 → 0.9.2
Bump version: 0.9.1 → 0.9.2
Released on 2016-06-15.
Backward incompatible change from 0.9: ~GenericTranslator.selector_to_xpath defaults to ignoring pseudo-elements, as it did in 0.8 and previous versio…
Released on 2013-10-17.
Backward incompatible change from 0.9: ~GenericTranslator.selector_to_xpath defaults to ignoring pseudo-elements, as it did in 0.8 and previous versions. (~GenericTranslator.css_to_xpath doesn’t change.)
Drop official support for Python 2.4 and 3.1, as testing was becoming difficult. Nothing will break overnight, but future releases may on may not work on these versions. Older releases will remain available on PyPI.
*Update:* This version accidentally introduced a backward incompatible change: ~GenericTranslator.selector_to_xpath defaults to rejecting pseudo-eleme…
Released on 2013-10-11.
Add parser support for functional pseudo-elements.
Update: This version accidentally introduced a backward incompatible change: ~GenericTranslator.selector_to_xpath defaults to rejecting pseudo-elements instead of ignoring them.
Released on 2013-03-15. Improvements: * #22 _ Let extended translators override what XPathExpr class is used * #19 _ Use the built-in lang() XPath fun
Released on 2013-03-15.
Improvements:
#22 <https://github.com/SimonSapin/cssselect/issues/22>_
Let extended translators override what XPathExpr class is used#19 <https://github.com/SimonSapin/cssselect/issues/19>_
Use the built-in lang() XPath function
for implementing the :lang() pseudo-class
with XML documents.
This is probably faster than ancestor-or-self::.Bug fixes:
#14 <https://github.com/SimonSapin/cssselect/issues/14>_
Fix non-ASCII pseudo-classes. (Invalid selector instead of crash.)#20 <https://github.com/SimonSapin/cssselect/issues/20>_
As per the spec, elements containing only whitespace are not considered empty
for the :empty pseudo-class.Released on 2012-06-14. Code name *remember-to-test-with-tox*.
Released on 2012-06-14. Code name remember-to-test-with-tox.
0.7 broke the parser in Python 2.4 and 2.5; the tests in 2.x. Now all is well again.
Also, pseudo-elements are now correctly made lower-case. (They are supposed to be case-insensitive.)
Bug fix release: see #2, #7 and #10 on GitHub.
Released on 2012-06-14.
Bug fix release: see #2, #7 and #10 on GitHub.
~=, ^= and *= attribute operators now correctly never match
when used with an empty string.Make sure that internal token objects do not "leak" into the public API and Selector.pseudo_element is an unicode string.
Released on 2012-04-25.
Make sure that internal token objects do not "leak" into the public API and Selector.pseudo_element is an unicode string.
In setup.py use setuptools/distribute if available, but fall back on distutils.
Released on 2012-04-24.
setup.py use setuptools/distribute if available, but fall back
on distutils.:lang() pseudo-class, although it is only based on
xml:lang or lang attributes. If the document language is known from
some other meta-data (like a Content-Language HTTP header or <meta>
element), a workaround is to set a lang attribute on the root element.Implement HTMLTranslator based on the HTML5 specification_ rather than guessing; add the xhtml parameter.
Released on 2012-04-20.
Fix case sensitivity issues.
Implement HTMLTranslator based on the HTML5 specification rather than guessing; add the xhtml parameter.
Several bug fixes and better test coverage.
Add proper support for pseudo-elements
Released on 2012-04-18.
Add proper support for pseudo-elements
Add specificity calculation
Expose the parse function and the parsed Selector objects in the API.
Add the ~GenericTranslator.selector_to_xpath method.
Rename the Translator class to GenericTranslator
Released on 2012-04-17.
Fix many parsing bugs.
Rename the Translator class to GenericTranslator
There, implement :target, :hover, :focus, :active :checked, :enabled, :disabled, :link and :visited as never matching.
Make a new HTML-specific HTMLTranslator subclass. There, implement :checked, :enabled, :disabled, :link and :visited as appropriate for HTML, with all links "not visited".
Remove the css_to_xpath function. The translator classes are the new API.
Add support for :contains() back, but case-sensitive. lxml will override it to be case-insensitive for backward-compatibility.
Discussion is open if anyone is interested in implementing eg. :target or :visited differently, but they can always do it in a Translator subclass.
Remove the CSSSelector class. (The css_to_xpath() function is now the main API.)
Released on 2012-04-16.
CSSSelector class. (The css_to_xpath() function is now
the main API.):contains() pseudo-class.These changes allow cssselect to be used without lxml. (Hey, this was the whole point of this project.) The tests still require lxml, though. The removed parts are expected to stay in lxml for backward-compatibility.
:contains() only existed in an early draft <http://www.w3.org/TR/2001/CR-css3-selectors-20011113/#content-selectors>_
of the Selectors specification, and was removed before Level 3 stabilized.
Internally, it used a custom XPath extension function which can be
difficult to express outside of lxml.
Translator class.Subclasses of Translator can be made to change the way that some selector
(eg. a pseudo-class) is implemented.
Extract lxml.cssselect from the rest of lxml and make it a stand-alone project.
Released on 2012-04-13.
Extract lxml.cssselect from the rest of lxml and make it a stand-alone project.
Commit ea53ceaf7e44ba4fbb5c818ae31370932f47774e was taken on 2012-04-11
from the 'master' branch of lxml’s git repository. This is somewhere
between versions 2.3.4 and 2.4.
The commit history has been rewritten to:
This project has its own import name, tests and documentation. But the code itself is unchanged and still depends on lxml.
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →