diff --git a/.appveyor.yml b/.appveyor.yml index a1a3e347..8af60b9b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -# To activate, change the Appveyor settings to use `.appveyor.yml`. +image: Visual Studio 2019 environment: global: PATH: "C:\\Python27\\Scripts\\;%PATH%" @@ -13,6 +13,10 @@ environment: - TOXENV: py37-optional - TOXENV: py38-base - TOXENV: py38-optional + - TOXENV: py39-base + - TOXENV: py39-optional + - TOXENV: py310-base + - TOXENV: py310-optional install: - git submodule update --init --recursive diff --git a/.github/workflows/python-tox.yml b/.github/workflows/python-tox.yml index ec5cf636..0e3e46db 100644 --- a/.github/workflows/python-tox.yml +++ b/.github/workflows/python-tox.yml @@ -6,15 +6,18 @@ jobs: if: github.event.push || github.event.pull_request.head.repo.full_name != github.repository runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - python: [2.7, 3.5, 3.6, 3.7, 3.8, pypy-2.7, pypy3] + python: ["2.7", "3.7", "3.8", "3.9", "3.10", "3.11", "pypy-2.7", "pypy-3.8"] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: true - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} + cache: pip + cache-dependency-path: "requirements*.txt" - run: pip install tox - run: tox -e py - if: ${{ always() }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d2d9e30e..00000000 --- a/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -language: python -python: - - "pypy3" - - "pypy" - - "3.8" - - "3.7" - - "3.6" - - "3.5" - - "2.7" - - "3.9-dev" - -cache: pip - -env: - global: - - TOXENV=base,optional,six19-optional - -install: - - pip install tox - -script: - - tox - -after_script: - - python debug-info.py diff --git a/CHANGES.rst b/CHANGES.rst index 0f6314aa..3ed63a96 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -95,7 +95,7 @@ Released on July 14, 2016 tested, doesn't entirely work, and as far as I can tell is completely unused by anyone.** -* Move testsuite to ``py.test``. +* Move testsuite to ``pytest``. * **Fix #124: move to webencodings for decoding the input byte stream; this makes html5lib compliant with the Encoding Standard, and diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 8c5e1985..dba35216 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -16,7 +16,7 @@ documentation. Some useful information: - We keep the master branch passing all tests at all times on all supported versions. -`Travis CI `_ is run +`GitHub Actions `_ is run against all pull requests and should enforce all of the above. We use `Opera Critic `_ as an external diff --git a/README.rst b/README.rst index d367905d..a17411ab 100644 --- a/README.rst +++ b/README.rst @@ -1,9 +1,8 @@ html5lib ======== -.. image:: http://travis-ci.org/html5lib/html5lib-python.svg?branch=master - :target: http://travis-ci.org/html5lib/html5lib-python - +.. image:: http://github.com/html5lib/html5lib-python/actions/workflows/python-tox.yml/badge.svg + :target: http://github.com/html5lib/html5lib-python/actions/workflows/python-tox.yml html5lib is a pure-python library for parsing HTML. It is designed to conform to the WHATWG HTML specification, as is implemented by all major @@ -128,7 +127,7 @@ Tests ----- Unit tests require the ``pytest`` and ``mock`` libraries and can be -run using the ``py.test`` command in the root directory. +run using the ``pytest`` command in the root directory. Test data are contained in a separate `html5lib-tests `_ repository and included @@ -145,7 +144,9 @@ which can be found on PyPI. Questions? ---------- -There's a mailing list available for support on Google Groups, -`html5lib-discuss `_, -though you may get a quicker response asking on IRC in `#whatwg on -irc.freenode.net `_. +Check out `the docs http://html5lib.readthedocs.io/en/latest/`_. Still +need help? Go to our `GitHub Discussions +http://github.com/html5lib/html5lib-python/discussions`_. + +You can also browse the archives of the `html5lib-discuss mailing list +http://www.mail-archive.com/html5lib-discuss@googlegroups.com/`_. diff --git a/html5lib/_inputstream.py b/html5lib/_inputstream.py index 0207dd21..a93b5a4e 100644 --- a/html5lib/_inputstream.py +++ b/html5lib/_inputstream.py @@ -324,7 +324,7 @@ def charsUntil(self, characters, opposite=False): except KeyError: if __debug__: for c in characters: - assert(ord(c) < 128) + assert ord(c) < 128 regex = "".join(["\\x%02x" % ord(c) for c in characters]) if not opposite: regex = "^%s" % regex diff --git a/html5lib/html5parser.py b/html5lib/html5parser.py index 74d829d9..9fb038b7 100644 --- a/html5lib/html5parser.py +++ b/html5lib/html5parser.py @@ -1002,8 +1002,8 @@ def processCharacters(self, token): self.tree.insertText(token["data"]) # This must be bad for performance if (self.parser.framesetOK and - any([char not in spaceCharacters - for char in token["data"]])): + any(char not in spaceCharacters + for char in token["data"])): self.parser.framesetOK = False def processSpaceCharactersNonPre(self, token): @@ -1850,7 +1850,7 @@ def __init__(self, *args, **kwargs): def flushCharacters(self): data = "".join([item["data"] for item in self.characterTokens]) - if any([item not in spaceCharacters for item in data]): + if any(item not in spaceCharacters for item in data): token = {"type": tokenTypes["Characters"], "data": data} self.parser.phases["inTable"].insertText(token) elif data: diff --git a/html5lib/serializer.py b/html5lib/serializer.py index c66df683..a171ac1c 100644 --- a/html5lib/serializer.py +++ b/html5lib/serializer.py @@ -222,14 +222,14 @@ def __init__(self, **kwargs): self.strict = False def encode(self, string): - assert(isinstance(string, text_type)) + assert isinstance(string, text_type) if self.encoding: return string.encode(self.encoding, "htmlentityreplace") else: return string def encodeStrict(self, string): - assert(isinstance(string, text_type)) + assert isinstance(string, text_type) if self.encoding: return string.encode(self.encoding, "strict") else: diff --git a/html5lib/tests/support.py b/html5lib/tests/support.py index 9cd5afbe..1bd0ccc1 100644 --- a/html5lib/tests/support.py +++ b/html5lib/tests/support.py @@ -8,7 +8,7 @@ import glob import xml.sax.handler -base_path = os.path.split(__file__)[0] +base_path = os.path.dirname(__file__) test_dir = os.path.join(base_path, 'testdata') sys.path.insert(0, os.path.abspath(os.path.join(base_path, diff --git a/html5lib/tests/test_sanitizer.py b/html5lib/tests/test_sanitizer.py index f3faeb80..6ad43a3a 100644 --- a/html5lib/tests/test_sanitizer.py +++ b/html5lib/tests/test_sanitizer.py @@ -1,9 +1,14 @@ from __future__ import absolute_import, division, unicode_literals +import warnings + import pytest from html5lib import constants, parseFragment, serialize -from html5lib.filters import sanitizer + +with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + from html5lib.filters import sanitizer def sanitize_html(stream): diff --git a/html5lib/tests/test_serializer.py b/html5lib/tests/test_serializer.py index bce62459..a2be0be5 100644 --- a/html5lib/tests/test_serializer.py +++ b/html5lib/tests/test_serializer.py @@ -74,7 +74,7 @@ def _convertAttrib(self, attribs): attrs = {} for attrib in attribs: name = (attrib["namespace"], attrib["name"]) - assert(name not in attrs) + assert name not in attrs attrs[name] = attrib["value"] return attrs diff --git a/html5lib/tests/tokenizertotree.py b/html5lib/tests/tokenizertotree.py index 8528e876..42463f32 100644 --- a/html5lib/tests/tokenizertotree.py +++ b/html5lib/tests/tokenizertotree.py @@ -29,7 +29,7 @@ def run_file(filename, out_path): except ValueError: sys.stderr.write("Failed to load %s\n" % filename) return - name = os.path.splitext(os.path.split(filename)[1])[0] + name = os.path.splitext(os.path.basename(filename))[0] output_file = open(os.path.join(out_path, "tokenizer_%s.dat" % name), "w") if 'tests' in tests_data: diff --git a/html5lib/treebuilders/etree.py b/html5lib/treebuilders/etree.py index 086bed4e..0b745081 100644 --- a/html5lib/treebuilders/etree.py +++ b/html5lib/treebuilders/etree.py @@ -108,7 +108,7 @@ def removeChild(self, node): node.parent = None def insertText(self, data, insertBefore=None): - if not(len(self._element)): + if not len(self._element): if not self._element.text: self._element.text = "" self._element.text += data @@ -201,7 +201,7 @@ def testSerializer(element): rv = [] def serializeElement(element, indent=0): - if not(hasattr(element, "tag")): + if not hasattr(element, "tag"): element = element.getroot() if element.tag == "": if element.get("publicId") or element.get("systemId"): diff --git a/html5lib/treewalkers/etree.py b/html5lib/treewalkers/etree.py index 44653372..411a1d45 100644 --- a/html5lib/treewalkers/etree.py +++ b/html5lib/treewalkers/etree.py @@ -37,7 +37,7 @@ def getNodeDetails(self, node): else: node = elt - if not(hasattr(node, "tag")): + if not hasattr(node, "tag"): node = node.getroot() if node.tag in ("DOCUMENT_ROOT", "DOCUMENT_FRAGMENT"): diff --git a/pytest.ini b/pytest.ini index 8824977a..1f620d98 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,6 +1,6 @@ [pytest] # Output fails, errors, xpass, and warnings; ignore doctest; make warnings errors -addopts = -rfEXw -p no:doctest --strict +addopts = -rfEXw -p no:doctest --strict-markers # Make xpass results be considered fail xfail_strict = true diff --git a/requirements-test.txt b/requirements-test.txt index 57f8f617..8c0ca7c7 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,7 +1,7 @@ -r requirements.txt tox>=3.15.1,<4 -flake8>=3.8.1,<3.9 +flake8>=3.8.1,<6 pytest>=4.6.10,<5 ; python_version < '3' pytest>=5.4.2,<7 ; python_version >= '3' coverage>=5.1,<6 diff --git a/setup.py b/setup.py index f84c1284..b4c11811 100644 --- a/setup.py +++ b/setup.py @@ -70,6 +70,9 @@ def default_environment(): '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', + 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries :: Python Modules', diff --git a/tox.ini b/tox.ini index 16b8cf41..42790f48 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py{27,35,36,37,38,py,py3}-{base,six19,optional} +envlist = py{27,35,36,37,38,39,310,311,py,py3}-{base,six19,optional} [testenv] deps = @@ -12,7 +12,7 @@ passenv = COVERAGE_RUN_OPTIONS commands = six19: pip install six==1.9 - {env:PYTEST_COMMAND:{envbindir}/py.test} {posargs} + {env:PYTEST_COMMAND:{envbindir}/pytest} {posargs} flake8 {toxinidir} [testenv:doc]