diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6c6ffeab..391e8176 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,11 +17,8 @@ jobs: max-parallel: 4 matrix: platform: [ubuntu-latest, windows-latest] - tox-env: [py36, py37, py38, py39, py310, nolxml, nohtml5lib] + tox-env: [py37, py38, py39, py310, nolxml, nohtml5lib] include: - - tox-env: py36 - python-version: 3.6 - continue-on-error: false - tox-env: py37 python-version: 3.7 continue-on-error: false @@ -60,7 +57,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip setuptools tox coverage codecov + python -m pip install --upgrade pip setuptools build tox coverage codecov - name: Test run: | python -m tox diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 220449ec..fdb83e7b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -37,10 +37,6 @@ jobs: git push gh-token gh-pages pypi: - strategy: - matrix: - distribution: [bdist_wheel, sdist] - runs-on: ubuntu-latest steps: @@ -50,10 +46,10 @@ jobs: python-version: 3.9 - name: Package run: | - pip install --upgrade setuptools wheel - python setup.py ${{ matrix.distribution }} + pip install --upgrade build + python -m build -s -w - name: Publish - uses: pypa/gh-action-pypi-publish@v1.4.1 + uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.PYPI_TOKEN }} diff --git a/LICENSE.md b/LICENSE.md index d8fc0d16..38adcc8d 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018 - 2021 Isaac Muse +Copyright (c) 2018 - 2022 Isaac Muse Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 7c4a664b..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1,16 +0,0 @@ -recursive-include soupsieve *.py py.typed -recursive-include tests *.py -recursive-include docs/src/markdown *.md *.png *.gif *.html -recursive-include docs/src/dictionary *.txt -recursive-include docs/theme *.js *.css *.html -recursive-include requirements *.txt -recursive-exclude site * -include .pyspelling.yml -include mkdocs.yml -include setup.py -include setup.cfg -include tox.ini -include LICENSE.md -include README.md -include MANIFEST.in -include pyproject.toml diff --git a/README.md b/README.md index f6f8cb2d..d7474231 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ Documentation is found here: https://facelessuser.github.io/soupsieve/. MIT License -Copyright (c) 2018 - 2021 Isaac Muse +Copyright (c) 2018 - 2022 Isaac Muse Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the diff --git a/docs/src/markdown/_snippets/abbr.txt b/docs/src/markdown/.snippets/abbr.md similarity index 100% rename from docs/src/markdown/_snippets/abbr.txt rename to docs/src/markdown/.snippets/abbr.md diff --git a/docs/src/markdown/_snippets/links.txt b/docs/src/markdown/.snippets/links.md similarity index 100% rename from docs/src/markdown/_snippets/links.txt rename to docs/src/markdown/.snippets/links.md diff --git a/docs/src/markdown/.snippets/refs.md b/docs/src/markdown/.snippets/refs.md new file mode 100644 index 00000000..a3583e70 --- /dev/null +++ b/docs/src/markdown/.snippets/refs.md @@ -0,0 +1,4 @@ +--8<-- +links.md +abbr.md +--8<-- diff --git a/docs/src/markdown/_snippets/selector_styles.txt b/docs/src/markdown/.snippets/selector_styles.md similarity index 100% rename from docs/src/markdown/_snippets/selector_styles.txt rename to docs/src/markdown/.snippets/selector_styles.md diff --git a/docs/src/markdown/_snippets/refs.txt b/docs/src/markdown/_snippets/refs.txt deleted file mode 100644 index 1715a5c1..00000000 --- a/docs/src/markdown/_snippets/refs.txt +++ /dev/null @@ -1,4 +0,0 @@ ---8<-- -links.txt -abbr.txt ---8<-- diff --git a/docs/src/markdown/about/changelog.md b/docs/src/markdown/about/changelog.md index 5baba14e..2306cb0f 100644 --- a/docs/src/markdown/about/changelog.md +++ b/docs/src/markdown/about/changelog.md @@ -1,8 +1,12 @@ # Changelog +## 2.3.2 + +- **FIX**: Fix some typos in error messages. + ## 2.3.1 -- **FIX**: Ensure attribute selectors match tags that have new lines characters in attributes. (#233) +- **FIX**: Ensure attribute selectors match tags that have new line characters in attributes. (#233) ## 2.3 diff --git a/docs/src/markdown/about/development.md b/docs/src/markdown/about/development.md index 7609dc24..14ffd401 100644 --- a/docs/src/markdown/about/development.md +++ b/docs/src/markdown/about/development.md @@ -391,5 +391,3 @@ class SelectorLang: Attribute | Description ------------- | ----------- `languages` | A list of regular expression objects that match a language pattern. - ---8<-- "links.txt" diff --git a/docs/src/markdown/about/license.md b/docs/src/markdown/about/license.md index da1c24f6..57649608 100644 --- a/docs/src/markdown/about/license.md +++ b/docs/src/markdown/about/license.md @@ -1,23 +1,3 @@ # License -MIT License - -Copyright (c) 2018 - 2021 Isaac Muse - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +--8<-- "LICENSE.md" diff --git a/docs/src/markdown/api.md b/docs/src/markdown/api.md index 8f76fb60..edcbac6a 100644 --- a/docs/src/markdown/api.md +++ b/docs/src/markdown/api.md @@ -314,7 +314,3 @@ Tags do not necessarily have to have a prefix for Soup Sieve to recognize them e *should* automatically get the SVG namespace. Depending how namespaces were defined in the document, tags may inherit namespaces in some conditions. Namespace assignment is mainly handled by the parser and exposed through the Beautiful Soup API. Soup Sieve uses the Beautiful Soup API to then compare namespaces for supported documents. - ---8<-- -refs.txt ---8<-- diff --git a/docs/src/markdown/index.md b/docs/src/markdown/index.md index 58ed8be6..cb71e878 100644 --- a/docs/src/markdown/index.md +++ b/docs/src/markdown/index.md @@ -185,7 +185,3 @@ Compiled patterns are cached, so if for any reason you need to clear the cache, ```pycon3 >>> sv.purge() ``` - ---8<-- -refs.txt ---8<-- diff --git a/docs/src/markdown/selectors/basic.md b/docs/src/markdown/selectors/basic.md index f64dd107..16e2c86f 100644 --- a/docs/src/markdown/selectors/basic.md +++ b/docs/src/markdown/selectors/basic.md @@ -541,6 +541,5 @@ Namespaces can be used with attribute selectors as well except that when `[|attr ``` --8<-- -selector_styles.txt -refs.txt +selector_styles.md --8<-- diff --git a/docs/src/markdown/selectors/combinators.md b/docs/src/markdown/selectors/combinators.md index 2361fa1e..17da4310 100644 --- a/docs/src/markdown/selectors/combinators.md +++ b/docs/src/markdown/selectors/combinators.md @@ -152,6 +152,5 @@ has an adjacent sibling that precedes it that matches the first element. https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_combinator --8<-- -selector_styles.txt -refs.txt +selector_styles.md --8<-- diff --git a/docs/src/markdown/selectors/index.md b/docs/src/markdown/selectors/index.md index 39f14f34..18f09db1 100644 --- a/docs/src/markdown/selectors/index.md +++ b/docs/src/markdown/selectors/index.md @@ -117,6 +117,5 @@ A selector list is a list of selectors joined with a comma (`,`). A selector lis valid if any of the selectors in a list matches. --8<-- -selector_styles.txt -refs.txt +selector_styles.md --8<-- diff --git a/docs/src/markdown/selectors/pseudo-classes.md b/docs/src/markdown/selectors/pseudo-classes.md index 6a21a5db..17b22386 100644 --- a/docs/src/markdown/selectors/pseudo-classes.md +++ b/docs/src/markdown/selectors/pseudo-classes.md @@ -400,6 +400,12 @@ given element), match at least one element. While the level 4 specifications state that [compound](#compound-selector) selectors are supported, complex selectors are planned for level 5 CSS selectors. Soup Sieve supports [complex](#complex-selector) selectors. +In addition to supporting complex selectors, Soup Sieve also supports nested `:has()` which has been excluded from the +level 4 specifications to help encourage browsers to implement `:has()`. This exclusion helps to reduces complexity and +improves performance in a live environment. As these performance concerns are not an issue in a scraping environment +compared to a web browser, Soup Sieve has no intentions on restricting the nesting of `:has()`. Users can always choose +not to nest `:has()` if there are concerns. + === "Syntax" ```css :has(selector) @@ -1590,6 +1596,5 @@ Syntax is the same as [`:-soup-contains()`](#:-soup-contains). `:-soup-contains-own()` was added in 2.1. --8<-- -selector_styles.txt -refs.txt +selector_styles.md --8<-- diff --git a/docs/src/markdown/selectors/unsupported.md b/docs/src/markdown/selectors/unsupported.md index ec2ae847..69c67674 100644 --- a/docs/src/markdown/selectors/unsupported.md +++ b/docs/src/markdown/selectors/unsupported.md @@ -170,6 +170,5 @@ Selects links that have already been visited. ``` --8<-- -selector_styles.txt -refs.txt +selector_styles.md --8<-- diff --git a/hatch_build.py b/hatch_build.py new file mode 100644 index 00000000..00fe4652 --- /dev/null +++ b/hatch_build.py @@ -0,0 +1,51 @@ +"""Dynamically define some metadata.""" +import os + +from hatchling.metadata.plugin.interface import MetadataHookInterface + + +def get_version_dev_status(root): + """Get version_info without importing the entire module.""" + + import importlib.util + + path = os.path.join(root, "soupsieve", "__meta__.py") + spec = importlib.util.spec_from_file_location("__meta__", path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module.__version_info__._get_dev_status() + + +def get_requirements(root): + """Load list of dependencies.""" + + install_requires = [] + with open(os.path.join(root, "requirements", "project.txt")) as f: + for line in f: + if not line.startswith("#"): + install_requires.append(line.strip()) + return install_requires + + +class CustomMetadataHook(MetadataHookInterface): + """Our metadata hook.""" + + def update(self, metadata): + """See https://ofek.dev/hatch/latest/plugins/metadata-hook/ for more information.""" + + metadata["dependencies"] = get_requirements(self.root) + metadata["classifiers"] = [ + f"Development Status :: {get_version_dev_status(self.root)}", + 'Environment :: Console', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Typing :: Typed' + ] diff --git a/mkdocs.yml b/mkdocs.yml index c87b2876..7c8f0c86 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -4,7 +4,7 @@ repo_url: https://github.com/facelessuser/soupsieve edit_uri: tree/main/docs/src/markdown site_description: A modern CSS selector library for Beautiful Soup. copyright: | - Copyright © 2018 - 2021 Isaac Muse + Copyright © 2018 - 2022 Isaac Muse docs_dir: docs/src/markdown theme: @@ -86,7 +86,11 @@ markdown_extensions: - pymdownx.mark: - pymdownx.striphtml: - pymdownx.snippets: - base_path: docs/src/markdown/_snippets + base_path: + - docs/src/markdown/.snippets + - LICENSE.md + auto_append: + - refs.md - pymdownx.keys: separator: "\uff0b" - pymdownx.details: diff --git a/pyproject.toml b/pyproject.toml index 7cc7d615..3e9a168c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,14 +1,69 @@ [build-system] requires = [ - "setuptools>=42", - "wheel" + "hatchling>=0.21.1", ] +build-backend = "hatchling.build" -build-backend = "setuptools.build_meta" +[project] +name = "soupsieve" +description = "A modern CSS selector implementation for Beautiful Soup." +readme = "README.md" +license = "MIT" +requires-python = ">=3.6" +authors = [ + { name = "Isaac Muse", email = "Isaac.Muse@gmail.com" }, +] +keywords = [ + "CSS", + "HTML", + "XML", + "selector", + "filter", + "query", + "soup" +] +dynamic = [ + "classifiers", + "dependencies", + "version", +] + +[project.urls] +Homepage = "https://github.com/facelessuser/soupsieve" + +[tool.hatch.version] +source = "code" +path = "soupsieve/__meta__.py" + +[tool.hatch.build.targets.wheel] +include = [ + "/soupsieve", +] + +[tool.hatch.build.targets.sdist] +include = [ + "/docs/src/markdown/**/*.md", + "/docs/src/markdown/**/*.gif", + "/docs/src/markdown/**/*.png", + "/docs/src/markdown/dictionary/*.txt", + "/docs/theme/**/*.css", + "/docs/theme/**/*.js", + "/docs/theme/**/*.html", + "/requirements/*.txt", + "/soupsieve/**/*.py", + "/soupsieve/py.typed", + "/tests/**/*.py", + "/.pyspelling.yml", + "/.coveragerc", + "/mkdocs.yml", + "/tox.ini", +] [tool.mypy] files = [ - "soupsieve/*.py" + "soupsieve" ] strict = true show_error_codes = true + +[tool.hatch.metadata.hooks.custom] diff --git a/requirements/docs.txt b/requirements/docs.txt index 31f15efb..da942b50 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -1,4 +1,4 @@ -mkdocs_pymdownx_material_extras==1.5.5 +mkdocs_pymdownx_material_extras>=2.0 mkdocs-git-revision-date-localized-plugin mkdocs-minify-plugin pyspelling diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 21934a22..00000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[metadata] -license_file = LICENSE.md diff --git a/setup.py b/setup.py deleted file mode 100644 index 7370154b..00000000 --- a/setup.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -"""Setup Soup Sieve.""" -from setuptools import setup, find_packages -import os - - -def get_version(): - """Get version and version_info without importing the entire module.""" - - import importlib.util - - path = os.path.join(os.path.dirname(__file__), 'soupsieve', '__meta__.py') - spec = importlib.util.spec_from_file_location("__meta__", path) - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - vi = module.__version_info__ - return vi._get_canonical(), vi._get_dev_status() - - -def get_requirements(req): - """Load list of dependencies.""" - - install_requires = [] - with open(req) as f: - for line in f: - if not line.startswith("#"): - install_requires.append(line.strip()) - return install_requires - - -def get_description(): - """Get long description.""" - - with open("README.md", 'r') as f: - desc = f.read() - return desc - - -VER, DEVSTATUS = get_version() - -setup( - name='soupsieve', - version=VER, - python_requires=">=3.6", - keywords='CSS HTML XML selector filter query soup', - description='A modern CSS selector implementation for Beautiful Soup.', - long_description=get_description(), - long_description_content_type='text/markdown', - author='Isaac Muse', - author_email='Isaac.Muse@gmail.com', - url='https://github.com/facelessuser/soupsieve', - packages=find_packages(exclude=['test*', 'tools']), - package_data={"soupsieve": ["py.typed"]}, - install_requires=get_requirements("requirements/project.txt"), - license='MIT License', - classifiers=[ - 'Development Status :: %s' % DEVSTATUS, - 'Environment :: Console', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Operating System :: OS Independent', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'Typing :: Typed' - ] -) diff --git a/soupsieve/__meta__.py b/soupsieve/__meta__.py index 2d769fbf..15be0efa 100644 --- a/soupsieve/__meta__.py +++ b/soupsieve/__meta__.py @@ -192,5 +192,5 @@ def parse_version(ver: str) -> Version: return Version(major, minor, micro, release, pre, post, dev) -__version_info__ = Version(2, 3, 1, "final") +__version_info__ = Version(2, 3, 2, "final") __version__ = __version_info__._get_canonical() diff --git a/tox.ini b/tox.ini index f2f6ad06..408d8d72 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,7 @@ [tox] +isolated_build = true envlist = - py36,py37,py38,py39,py310, + py37,py38,py39,py310, lint, nolxml, nohtml5lib [testenv]