From 62da3cd097a80218af6495233d797ed65215287c Mon Sep 17 00:00:00 2001 From: Isaac Muse Date: Thu, 31 Aug 2023 10:39:27 -0600 Subject: [PATCH] Use Ruff linter and consolidate tox stuff to pyproject.toml (#266) * Use Ruff linter and consolidate tox stuff to pyproject.toml * Use Python 3.11 for generic actions * Don't try to bundle tox.ini as it is now gone --- .github/workflows/build.yml | 4 +- .github/workflows/deploy.yml | 4 +- docs/src/markdown/about/development.md | 12 +--- hatch_build.py | 12 ---- pyproject.toml | 98 +++++++++++++++++++++++++- requirements/lint.txt | 7 +- requirements/project.txt | 0 soupsieve/css_match.py | 8 +-- soupsieve/css_parser.py | 2 +- soupsieve/css_types.py | 18 ++--- soupsieve/pretty.py | 3 +- tests/test_api.py | 26 +++---- tests/test_bs4_cases.py | 10 +-- tests/test_level2/test_attribute.py | 18 ++--- tests/test_level3/test_not.py | 4 +- tests/test_level3/test_root.py | 20 ++---- tests/test_level4/test_scope.py | 16 ++--- tests/test_quirks.py | 4 +- tests/util.py | 7 +- tox.ini | 56 --------------- 20 files changed, 158 insertions(+), 171 deletions(-) delete mode 100644 requirements/project.txt delete mode 100644 tox.ini diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fc859b59..8e39a8d4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -82,7 +82,7 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: [3.9] + python-version: [3.11] env: TOXENV: lint @@ -106,7 +106,7 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: [3.9] + python-version: [3.11] env: TOXENV: documents diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 0716e3c9..d47e568f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -11,7 +11,7 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: [3.9] + python-version: [3.11] runs-on: ubuntu-latest @@ -43,7 +43,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: 3.11 - name: Package run: | pip install --upgrade build diff --git a/docs/src/markdown/about/development.md b/docs/src/markdown/about/development.md index 49d93312..a25b21e2 100644 --- a/docs/src/markdown/about/development.md +++ b/docs/src/markdown/about/development.md @@ -25,15 +25,9 @@ Directory | Description ## Coding Standards -When writing code, the code should roughly conform to PEP8 and PEP257 suggestions. The project utilizes the Flake8 -linter (with some additional plugins) to ensure code conforms (give or take some of the rules). When in doubt, follow -the formatting hints of existing code when adding files or modifying existing files. Listed below are the modules used: - -- @gitlab:pycqa/flake8 -- @gitlab:pycqa/flake8-docstrings -- @gitlab:pycqa/pep8-naming -- @ebeweber/flake8-mutable -- @gforcada/flake8-builtins +When writing code, the code should roughly conform to PEP8 and PEP257 suggestions along with some other requirements. +The project utilizes the @astral-sh/ruff linter that helps to ensure code conforms (give or take some of the rules). +When in doubt, follow the formatting hints of existing code when adding files or modifying existing files. Usually this can be automated with Tox (assuming it is installed): `tox -e lint`. diff --git a/hatch_build.py b/hatch_build.py index 10afd28a..7e3a3fad 100644 --- a/hatch_build.py +++ b/hatch_build.py @@ -16,24 +16,12 @@ def get_version_dev_status(root): 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', diff --git a/pyproject.toml b/pyproject.toml index d3af3863..e53431b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,6 @@ keywords = [ ] dynamic = [ "classifiers", - "dependencies", "version", ] @@ -55,8 +54,7 @@ include = [ "/tests/**/*.py", "/.pyspelling.yml", "/.coveragerc", - "/mkdocs.yml", - "/tox.ini", + "/mkdocs.yml" ] [tool.mypy] @@ -67,3 +65,97 @@ strict = true show_error_codes = true [tool.hatch.metadata.hooks.custom] + +[tool.ruff] +line-length = 120 + +select = [ + "A", # flake8-builtins + "B", # flake8-bugbear + "D", # pydocstyle + "C4", # flake8-comprehensions + "N", # pep8-naming + "E", # pycodestyle + "F", # pyflakes + "PGH", # pygrep-hooks + "RUF", # ruff + # "UP", # pyupgrade + "W", # pycodestyle + "YTT", # flake8-2020, + "PERF" # Perflint +] + +ignore = [ + "E741", + "D202", + "D401", + "D212", + "D203", + "N802", + "N801", + "N803", + "N806", + "N818", + "RUF012", + "RUF005", + "PGH004", + "RUF100" +] + +[tool.tox] +legacy_tox_ini = """ +[tox] +isolated_build = true +envlist = + py{38,39,310,311,312}, + lint, nolxml, nohtml5lib + +[testenv] +passenv = * +deps = + -rrequirements/tests.txt +commands = + mypy + pytest --cov soupsieve --cov-append {toxinidir} + coverage html -d {envtmpdir}/coverage + coverage xml + coverage report --show-missing + +[testenv:documents] +passenv = * +deps = + -rrequirements/docs.txt +commands = + mkdocs build --clean --verbose --strict + pyspelling + +[testenv:lint] +passenv = * +deps = + -rrequirements/lint.txt +commands = + "{envbindir}"/ruff check . + +[testenv:nolxml] +passenv = * +deps = + -rrequirements/tests-nolxml.txt +commands = + pytest {toxinidir} + +[testenv:nohtml5lib] +passenv = * +deps = + -rrequirements/tests-nohtml5lib.txt +commands = + pytest {toxinidir} + +[flake8] +exclude=build/*,.tox/* +max-line-length=120 +ignore=D202,D203,D401,E741,W504,N817,N818 + +[pytest] +filterwarnings = + ignore:\nCSS selector pattern:UserWarning +""" diff --git a/requirements/lint.txt b/requirements/lint.txt index 79574a5a..af3ee576 100644 --- a/requirements/lint.txt +++ b/requirements/lint.txt @@ -1,6 +1 @@ -flake8 -pydocstyle<4.0.0 -flake8_docstrings -pep8-naming -flake8-mutable -flake8-builtins +ruff diff --git a/requirements/project.txt b/requirements/project.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/soupsieve/css_match.py b/soupsieve/css_match.py index e483de96..1b003db8 100644 --- a/soupsieve/css_match.py +++ b/soupsieve/css_match.py @@ -282,7 +282,7 @@ def has_html_ns(el: bs4.Tag) -> bool: like we do in the case of `is_html_tag`. """ - ns = getattr(el, 'namespace') if el else None + ns = getattr(el, 'namespace') if el else None # noqa: B009 return bool(ns and ns == NS_XHTML) @staticmethod @@ -1271,11 +1271,7 @@ def match_dir(self, el: bs4.Tag, directionality: int) -> bool: # Auto handling for text inputs if ((is_input and itype in ('text', 'search', 'tel', 'url', 'email')) or is_textarea) and direction == 0: if is_textarea: - temp = [] - for node in self.get_contents(el, no_iframe=True): - if self.is_content_string(node): - temp.append(node) - value = ''.join(temp) + value = ''.join(node for node in self.get_contents(el, no_iframe=True) if self.is_content_string(node)) else: value = cast(str, self.get_attribute_by_name(el, 'value', '')) if value: diff --git a/soupsieve/css_parser.py b/soupsieve/css_parser.py index a4b40580..7813f3b3 100644 --- a/soupsieve/css_parser.py +++ b/soupsieve/css_parser.py @@ -869,7 +869,7 @@ def parse_pseudo_contains(self, sel: _Selector, m: Match[str], has_selector: boo pseudo = util.lower(css_unescape(m.group('name'))) if pseudo == ":contains": - warnings.warn( + warnings.warn( # noqa: B028 "The pseudo class ':contains' is deprecated, ':-soup-contains' should be used moving forward.", FutureWarning ) diff --git a/soupsieve/css_types.py b/soupsieve/css_types.py index 37ffe7f4..a92153b2 100644 --- a/soupsieve/css_types.py +++ b/soupsieve/css_types.py @@ -59,7 +59,7 @@ def __eq__(self, other: Any) -> bool: return ( isinstance(other, self.__base__()) and - all([getattr(other, key) == getattr(self, key) for key in self.__slots__ if key != '_hash']) + all(getattr(other, key) == getattr(self, key) for key in self.__slots__ if key != '_hash') ) def __ne__(self, other: Any) -> bool: @@ -67,7 +67,7 @@ def __ne__(self, other: Any) -> bool: return ( not isinstance(other, self.__base__()) or - any([getattr(other, key) != getattr(self, key) for key in self.__slots__ if key != '_hash']) + any(getattr(other, key) != getattr(self, key) for key in self.__slots__ if key != '_hash') ) def __hash__(self) -> int: @@ -112,9 +112,9 @@ def _validate(self, arg: dict[Any, Any] | Iterable[tuple[Any, Any]]) -> None: """Validate arguments.""" if isinstance(arg, dict): - if not all([isinstance(v, Hashable) for v in arg.values()]): + if not all(isinstance(v, Hashable) for v in arg.values()): raise TypeError(f'{self.__class__.__name__} values must be hashable') - elif not all([isinstance(k, Hashable) and isinstance(v, Hashable) for k, v in arg]): + elif not all(isinstance(k, Hashable) and isinstance(v, Hashable) for k, v in arg): raise TypeError(f'{self.__class__.__name__} values must be hashable') def __iter__(self) -> Iterator[Any]: @@ -157,9 +157,9 @@ def _validate(self, arg: dict[str, str] | Iterable[tuple[str, str]]) -> None: """Validate arguments.""" if isinstance(arg, dict): - if not all([isinstance(v, str) for v in arg.values()]): + if not all(isinstance(v, str) for v in arg.values()): raise TypeError(f'{self.__class__.__name__} values must be hashable') - elif not all([isinstance(k, str) and isinstance(v, str) for k, v in arg]): + elif not all(isinstance(k, str) and isinstance(v, str) for k, v in arg): raise TypeError(f'{self.__class__.__name__} keys and values must be Unicode strings') @@ -175,9 +175,9 @@ def _validate(self, arg: dict[str, str] | Iterable[tuple[str, str]]) -> None: """Validate arguments.""" if isinstance(arg, dict): - if not all([isinstance(v, str) for v in arg.values()]): + if not all(isinstance(v, str) for v in arg.values()): raise TypeError(f'{self.__class__.__name__} values must be hashable') - elif not all([isinstance(k, str) and isinstance(v, str) for k, v in arg]): + elif not all(isinstance(k, str) and isinstance(v, str) for k, v in arg): raise TypeError(f'{self.__class__.__name__} keys and values must be Unicode strings') @@ -367,7 +367,7 @@ def __init__( """Initialize.""" super().__init__( - selectors=tuple(selectors) if selectors is not None else tuple(), + selectors=tuple(selectors) if selectors is not None else (), is_not=is_not, is_html=is_html ) diff --git a/soupsieve/pretty.py b/soupsieve/pretty.py index 2841c893..b7980a8a 100644 --- a/soupsieve/pretty.py +++ b/soupsieve/pretty.py @@ -10,7 +10,7 @@ hasn't been tested extensively to make sure we aren't missing corners). Example: - +------- ``` >>> import soupsieve as sv >>> sv.compile('this > that.class[name=value]').selectors.pretty() @@ -64,6 +64,7 @@ is_not=False, is_html=False) ``` + """ from __future__ import annotations import re diff --git a/tests/test_api.py b/tests/test_api.py index 10dd3aa6..5e49558e 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -31,9 +31,7 @@ def test_select(self): """ soup = self.soup(markup, 'html.parser') - ids = [] - for el in sv.select('span[id]', soup): - ids.append(el.attrs['id']) + ids = [el.attrs['id'] for el in sv.select('span[id]', soup)] self.assertEqual(sorted(['5', 'some-id']), sorted(ids)) @@ -58,9 +56,7 @@ def test_select_order(self): """ soup = self.soup(markup, 'html.parser') - ids = [] - for el in sv.select('[id]', soup.body): - ids.append(el.attrs['id']) + ids = [el.attrs['id'] for el in sv.select('[id]', soup.body)] self.assertEqual(['1', '2', '3', '4', '5', 'some-id', '6'], ids) @@ -86,9 +82,7 @@ def test_select_limit(self): soup = self.soup(markup, 'html.parser') - ids = [] - for el in sv.select('span[id]', soup, limit=1): - ids.append(el.attrs['id']) + ids = [el.attrs['id'] for el in sv.select('span[id]', soup, limit=1)] self.assertEqual(sorted(['5']), sorted(ids)) @@ -163,9 +157,7 @@ def test_iselect(self): soup = self.soup(markup, 'html.parser') - ids = [] - for el in sv.iselect('span[id]', soup): - ids.append(el.attrs['id']) + ids = [el.attrs['id'] for el in sv.iselect('span[id]', soup)] self.assertEqual(sorted(['5', 'some-id']), sorted(ids)) @@ -190,9 +182,7 @@ def test_iselect_order(self): """ soup = self.soup(markup, 'html.parser') - ids = [] - for el in sv.iselect('[id]', soup): - ids.append(el.attrs['id']) + ids = [el.attrs['id'] for el in sv.iselect('[id]', soup)] self.assertEqual(['1', '2', '3', '4', '5', 'some-id', '6'], ids) @@ -297,7 +287,7 @@ def test_filter_list(self): """ soup = self.soup(markup, 'html.parser') - nodes = sv.filter('pre#\\36', [el for el in soup.html.body.children]) + nodes = sv.filter('pre#\\36', list(soup.html.body.children)) self.assertEqual(len(nodes), 1) self.assertEqual(nodes[0].attrs['id'], '6') @@ -462,8 +452,8 @@ def test_cache(self): sv.purge() self.assertEqual(sv.cp._cached_css_compile.cache_info().currsize, 0) - for x in range(1000): - value = f'[value="{str(random.randint(1, 10000))}"]' + for _x in range(1000): + value = f'[value="{random.randint(1, 10000)!s}"]' p = sv.compile(value) self.assertTrue(p.pattern == value) self.assertTrue(sv.cp._cached_css_compile.cache_info().currsize > 0) diff --git a/tests/test_bs4_cases.py b/tests/test_bs4_cases.py index 507330dc..26c11304 100644 --- a/tests/test_bs4_cases.py +++ b/tests/test_bs4_cases.py @@ -79,7 +79,7 @@ def test_parent_nth_of_type_preconditions(self): h1 = els[0] div_inner = h1.parent div_main = div_inner.parent - div_main_children = [child for child in div_main.children] + div_main_children = list(div_main.children) self.assertEqual(div_main_children[0], '\n') self.assertEqual(div_main_children[1], div_inner) @@ -100,9 +100,11 @@ def test_parent_nth_of_type(self): """.strip() -NAMESPACES = dict(x="http://www.w3.org/2003/05/soap-envelope", - y="http://www.w3.org/2005/08/addressing", - z="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd") +NAMESPACES = { + 'x': "http://www.w3.org/2003/05/soap-envelope", + 'y': "http://www.w3.org/2005/08/addressing", + 'z': "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" +} @util.requires_lxml diff --git a/tests/test_level2/test_attribute.py b/tests/test_level2/test_attribute.py index 920fc983..bdc0be6e 100644 --- a/tests/test_level2/test_attribute.py +++ b/tests/test_level2/test_attribute.py @@ -1,7 +1,7 @@ """Test attribute selector.""" from .. import util from soupsieve import SelectorSyntaxError -from bs4 import BeautifulSoup as BS +from bs4 import BeautifulSoup class TestAttribute(util.TestCase): @@ -375,14 +375,14 @@ def test_attribute_contains_cannot_have_escaped_spaces(self): def test_none_inputs(self): """Test weird inputs.""" - soup = BS('text', 'html.parser') + soup = BeautifulSoup('text', 'html.parser') soup.span['foo'] = None self.assertEqual(len(soup.select('span[foo]')), 1) def test_numeric_inputs(self): """Test weird inputs.""" - soup = BS('text', 'html.parser') + soup = BeautifulSoup('text', 'html.parser') soup.span['foo'] = 3 self.assertEqual(len(soup.select('span[foo="3"]')), 1) soup.span['foo'] = 3.3 @@ -391,29 +391,29 @@ def test_numeric_inputs(self): def test_sequence_inputs(self): """Test weird inputs.""" - soup = BS('text', 'html.parser') + soup = BeautifulSoup('text', 'html.parser') soup.span['foo'] = [3, "4"] self.assertEqual(len(soup.select('span[foo="3 4"]')), 1) def test_bytes_inputs(self): """Test weird inputs.""" - soup = BS('text', 'html.parser') + soup = BeautifulSoup('text', 'html.parser') soup.span['foo'] = b'test' self.assertEqual(len(soup.select('span[foo="test"]')), 1) def test_weird_inputs(self): """Test weird inputs.""" - soup = BS('text', 'html.parser') + soup = BeautifulSoup('text', 'html.parser') soup.span['foo'] = {'3': '4'} self.assertEqual(len(soup.select('span[foo="{\'3\': \'4\'}"]')), 1) def test_nested_sequences(self): - """Nested sequences will crash and burn due to the way BS handles them.""" + """Nested sequences will crash and burn due to the way BeautifulSoup handles them.""" # The exact exception is not important as it can fail in various locations for different reasons - with self.assertRaises(Exception): - soup = BS('text', 'html.parser') + with self.assertRaises(Exception): # noqa: B017 + soup = BeautifulSoup('text', 'html.parser') soup.span['foo'] = [['1']] soup.select("span['foo']") diff --git a/tests/test_level3/test_not.py b/tests/test_level3/test_not.py index 943fc106..ee1158b5 100644 --- a/tests/test_level3/test_not.py +++ b/tests/test_level3/test_not.py @@ -1,6 +1,6 @@ """Test not selectors.""" from .. import util -from bs4 import BeautifulSoup as BS +from bs4 import BeautifulSoup from soupsieve import SelectorSyntaxError @@ -53,7 +53,7 @@ def test_not_case(self): def test_none_inputs(self): """Test weird inputs.""" - soup = BS('text', 'html.parser') + soup = BeautifulSoup('text', 'html.parser') soup.span['foo'] = None self.assertEqual(len(soup.select('span:not([foo])')), 0) diff --git a/tests/test_level3/test_root.py b/tests/test_level3/test_root.py index 60f7e752..b3ec8b95 100644 --- a/tests/test_level3/test_root.py +++ b/tests/test_level3/test_root.py @@ -107,14 +107,10 @@ def test_iframe(self): soup = self.soup(self.MARKUP_IFRAME, 'html.parser') - ids = [] - for el in sv.select(':root div', soup.iframe.html): - ids.append(el['id']) + ids = [el['id'] for el in sv.select(':root div', soup.iframe.html)] self.assertEqual(sorted(ids), sorted(['div2'])) - ids = [] - for el in sv.select(':root > body > div', soup.iframe.html): - ids.append(el['id']) + ids = [el['id'] for el in sv.select(':root > body > div', soup.iframe.html)] self.assertEqual(sorted(ids), sorted(['div2'])) def test_no_root_double_tag(self): @@ -158,10 +154,8 @@ def test_root_whitespace(self):
""" - ids = [] soup = self.soup(markup, 'html.parser') - for el in soup.select(':root'): - ids.append(el['id']) + ids = [el['id'] for el in soup.select(':root')] self.assertEqual(sorted(ids), sorted(['1'])) def test_root_preprocess(self): @@ -172,10 +166,8 @@ def test_root_preprocess(self):
""" - ids = [] soup = self.soup(markup, 'html.parser') - for el in soup.select(':root'): - ids.append(el['id']) + ids = [el['id'] for el in soup.select(':root')] self.assertEqual(sorted(ids), sorted(['1'])) def test_root_doctype(self): @@ -187,8 +179,6 @@ def test_root_doctype(self):
""" - ids = [] soup = self.soup(markup, 'html.parser') - for el in soup.select(':root'): - ids.append(el['id']) + ids = [el['id'] for el in soup.select(':root')] self.assertEqual(sorted(ids), sorted(['1'])) diff --git a/tests/test_level4/test_scope.py b/tests/test_level4/test_scope.py index d4f333cc..ec050bcf 100644 --- a/tests/test_level4/test_scope.py +++ b/tests/test_level4/test_scope.py @@ -63,26 +63,18 @@ def test_scope_is_select_target(self): el = soup.html # Scope here means the current element under select - ids = [] - for el in sv.select(':scope div', el, flags=sv.DEBUG): - ids.append(el.attrs['id']) + ids = [el.attrs['id'] for el in sv.select(':scope div', el, flags=sv.DEBUG)] self.assertEqual(sorted(ids), sorted(['div'])) el = soup.body - ids = [] - for el in sv.select(':scope div', el, flags=sv.DEBUG): - ids.append(el.attrs['id']) + ids = [el.attrs['id'] for el in sv.select(':scope div', el, flags=sv.DEBUG)] self.assertEqual(sorted(ids), sorted(['div'])) # `div` is the current element under select, and it has no `div` elements. el = soup.div - ids = [] - for el in sv.select(':scope div', el, flags=sv.DEBUG): - ids.append(el.attrs['id']) + ids = [el.attrs['id'] for el in sv.select(':scope div', el, flags=sv.DEBUG)] self.assertEqual(sorted(ids), sorted([])) # `div` does have an element with the class `.wordshere` - ids = [] - for el in sv.select(':scope .wordshere', el, flags=sv.DEBUG): - ids.append(el.attrs['id']) + ids = [el.attrs['id'] for el in sv.select(':scope .wordshere', el, flags=sv.DEBUG)] self.assertEqual(sorted(ids), sorted(['pre'])) diff --git a/tests/test_quirks.py b/tests/test_quirks.py index 74934c21..2c6764c4 100644 --- a/tests/test_quirks.py +++ b/tests/test_quirks.py @@ -1,6 +1,6 @@ """Test quirky behaviors.""" from . import util -from bs4 import BeautifulSoup as BS +from bs4 import BeautifulSoup class TestQuirks(util.TestCase): @@ -13,7 +13,7 @@ def test_quirky_user_attrs(self):
test
""" - soup = BS(html, 'html.parser') + soup = BeautifulSoup(html, 'html.parser') soup.div.attrs['user'] = [['a']] print(soup.div.attrs) self.assertTrue(soup.select_one('div[user="[\'a\']"]') is not None) diff --git a/tests/util.py b/tests/util.py index a7af35e3..259d569d 100644 --- a/tests/util.py +++ b/tests/util.py @@ -103,9 +103,11 @@ def assert_raises(self, pattern, exception, namespace=None, custom=None): with self.assertRaises(exception): self.compile_pattern(pattern, namespaces=namespace, custom=custom) - def assert_selector(self, markup, selectors, expected_ids, namespaces={}, custom=None, flags=0): + def assert_selector(self, markup, selectors, expected_ids, namespaces=None, custom=None, flags=0): """Assert selector.""" + if namespaces is None: + namespaces = {} parsers = self.get_parsers(flags) print('----Running Selector Test----') @@ -123,7 +125,8 @@ def assert_selector(self, markup, selectors, expected_ids, namespaces={}, custom def available_parsers(*parsers): - """Filter a list of parsers, down to the available ones. + """ + Filter a list of parsers, down to the available ones. If there are none, report the test as skipped to pytest. """ diff --git a/tox.ini b/tox.ini deleted file mode 100644 index a3670c20..00000000 --- a/tox.ini +++ /dev/null @@ -1,56 +0,0 @@ -[tox] -isolated_build = true -envlist = - py{38,39,310,311,312}, - lint, nolxml, nohtml5lib - -[testenv] -passenv = * -deps = - -rrequirements/tests.txt -commands = - mypy - pytest --cov soupsieve --cov-append {toxinidir} - coverage html -d {envtmpdir}/coverage - coverage xml - coverage report --show-missing - -[testenv:documents] -passenv = * -deps = - -rrequirements/docs.txt - -rrequirements/project.txt -commands = - mkdocs build --clean --verbose --strict - pyspelling - -[testenv:lint] -passenv = * -deps = - -rrequirements/project.txt - -rrequirements/lint.txt -commands = - flake8 {toxinidir} - -[testenv:nolxml] -passenv = * -deps = - -rrequirements/tests-nolxml.txt -commands = - pytest {toxinidir} - -[testenv:nohtml5lib] -passenv = * -deps = - -rrequirements/tests-nohtml5lib.txt -commands = - pytest {toxinidir} - -[flake8] -exclude=build/*,.tox/* -max-line-length=120 -ignore=D202,D203,D401,E741,W504,N817,N818 - -[pytest] -filterwarnings = - ignore:\nCSS selector pattern:UserWarning