From c07ce3e8f7c9e7822f42713167d668c8b7bc59cc Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Sun, 17 Mar 2024 17:24:46 +0100 Subject: [PATCH] Use ruff instead of flake8 and isort --- .github/workflows/tests.yml | 4 +-- docs/contribute.rst | 9 +++---- pyproject.toml | 12 +++++---- tests/test_tinycss2.py | 51 ++++++++++++++++++------------------- tinycss2/nth.py | 2 +- tinycss2/parser.py | 21 +++++++-------- tinycss2/serializer.py | 3 +-- tinycss2/tokenizer.py | 23 +++++++---------- 8 files changed, 58 insertions(+), 67 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 294479e..a72b889 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -28,6 +28,4 @@ jobs: - name: Launch tests run: python -m pytest - name: Check coding style - run: python -m flake8 --exclude tests/css-parsing-tests - - name: Check imports order - run: python -m isort . --check --diff + run: python -m ruff check diff --git a/docs/contribute.rst b/docs/contribute.rst index c45c21f..62e77dc 100644 --- a/docs/contribute.rst +++ b/docs/contribute.rst @@ -45,15 +45,12 @@ You can launch tests using the following command:: venv/bin/python -m pytest -tinycss2 also uses isort_ to check imports and flake8_ to check the coding -style:: +tinycss2 also uses ruff_ to check the coding style:: - venv/bin/python -m isort . --check --diff - venv/bin/python -m flake8 --exclude tests/css-parsing-tests + venv/bin/python -m ruff check .. _pytest: https://docs.pytest.org/ -.. _isort: https://pycqa.github.io/isort/ -.. _flake8: https://flake8.pycqa.org/ +.. _ruff: https://docs.astral.sh/ruff/ Documentation diff --git a/pyproject.toml b/pyproject.toml index a5d3ee6..f240e0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,7 @@ Donation = 'https://opencollective.com/courtbouillon' [project.optional-dependencies] doc = ['sphinx', 'sphinx_rtd_theme'] -test = ['pytest', 'isort', 'flake8'] +test = ['pytest', 'ruff'] [tool.flit.sdist] exclude = ['.*'] @@ -56,7 +56,9 @@ include = ['tests/*', 'tinycss2/*'] exclude_lines = ['pragma: no cover', 'def __repr__', 'raise NotImplementedError'] omit = ['.*'] -[tool.isort] -default_section = 'FIRSTPARTY' -multi_line_output = 4 -extend_skip = ['tests/css-parsing-tests'] +[tool.ruff] +extend-exclude = ['tests/css-parsing-tests'] + +[tool.ruff.lint] +select = ['E', 'W', 'F', 'I', 'N', 'RUF'] +ignore = ['RUF001', 'RUF002', 'RUF003'] diff --git a/tests/test_tinycss2.py b/tests/test_tinycss2.py index d07aa69..2228ddc 100644 --- a/tests/test_tinycss2.py +++ b/tests/test_tinycss2.py @@ -4,19 +4,19 @@ from pathlib import Path import pytest -from tinycss2 import ( +from webencodings import Encoding, lookup + +from tinycss2 import ( # isort:skip parse_blocks_contents, parse_component_value_list, parse_declaration_list, - parse_one_component_value, parse_one_declaration, parse_one_rule, - parse_rule_list, parse_stylesheet, parse_stylesheet_bytes, serialize) -from tinycss2.ast import ( - AtKeywordToken, AtRule, Comment, CurlyBracketsBlock, Declaration, - DimensionToken, FunctionBlock, HashToken, IdentToken, LiteralToken, - NumberToken, ParenthesesBlock, ParseError, PercentageToken, QualifiedRule, - SquareBracketsBlock, StringToken, UnicodeRangeToken, URLToken, - WhitespaceToken) + parse_one_component_value, parse_one_declaration, parse_one_rule, parse_rule_list, + parse_stylesheet, parse_stylesheet_bytes, serialize) +from tinycss2.ast import ( # isort:skip + AtKeywordToken, AtRule, Comment, CurlyBracketsBlock, Declaration, DimensionToken, + FunctionBlock, HashToken, IdentToken, LiteralToken, NumberToken, ParenthesesBlock, + ParseError, PercentageToken, QualifiedRule, SquareBracketsBlock, StringToken, + UnicodeRangeToken, URLToken, WhitespaceToken) from tinycss2.color3 import RGBA, parse_color from tinycss2.nth import parse_nth -from webencodings import Encoding, lookup def generic(func): @@ -49,26 +49,25 @@ def numeric(t): LiteralToken: lambda t: t.value, IdentToken: lambda t: ['ident', t.value], AtKeywordToken: lambda t: ['at-keyword', t.value], - HashToken: lambda t: ['hash', t.value, - 'id' if t.is_identifier else 'unrestricted'], + HashToken: lambda t: [ + 'hash', t.value, 'id' if t.is_identifier else 'unrestricted'], StringToken: lambda t: ['string', t.value], URLToken: lambda t: ['url', t.value], - NumberToken: lambda t: ['number'] + numeric(t), - PercentageToken: lambda t: ['percentage'] + numeric(t), - DimensionToken: lambda t: ['dimension'] + numeric(t) + [t.unit], + NumberToken: lambda t: ['number', *numeric(t)], + PercentageToken: lambda t: ['percentage', *numeric(t)], + DimensionToken: lambda t: ['dimension', *numeric(t), t.unit], UnicodeRangeToken: lambda t: ['unicode-range', t.start, t.end], - CurlyBracketsBlock: lambda t: ['{}'] + to_json(t.content), - SquareBracketsBlock: lambda t: ['[]'] + to_json(t.content), - ParenthesesBlock: lambda t: ['()'] + to_json(t.content), - FunctionBlock: lambda t: ['function', t.name] + to_json(t.arguments), - - Declaration: lambda d: ['declaration', d.name, - to_json(d.value), d.important], - AtRule: lambda r: ['at-rule', r.at_keyword, to_json(r.prelude), - to_json(r.content)], - QualifiedRule: lambda r: ['qualified rule', to_json(r.prelude), - to_json(r.content)], + CurlyBracketsBlock: lambda t: ['{}', *to_json(t.content)], + SquareBracketsBlock: lambda t: ['[]', *to_json(t.content)], + ParenthesesBlock: lambda t: ['()', *to_json(t.content)], + FunctionBlock: lambda t: ['function', t.name, *to_json(t.arguments)], + + Declaration: lambda d: ['declaration', d.name, to_json(d.value), d.important], + AtRule: lambda r: [ + 'at-rule', r.at_keyword, to_json(r.prelude), to_json(r.content)], + QualifiedRule: lambda r: [ + 'qualified rule', to_json(r.prelude), to_json(r.content)], RGBA: lambda v: [round(c, 10) for c in v], } diff --git a/tinycss2/nth.py b/tinycss2/nth.py index 0c2ca77..c5e924b 100644 --- a/tinycss2/nth.py +++ b/tinycss2/nth.py @@ -88,7 +88,7 @@ def parse_b(tokens, a): def parse_signless_b(tokens, a, b_sign): token = _next_significant(tokens) if (token.type == 'number' and token.is_integer and - not token.representation[0] in '-+'): + token.representation[0] not in '-+'): return parse_end(tokens, a, b_sign * token.int_value) diff --git a/tinycss2/parser.py b/tinycss2/parser.py index 11dd519..f7c7e2f 100644 --- a/tinycss2/parser.py +++ b/tinycss2/parser.py @@ -135,8 +135,8 @@ def _parse_declaration(first_token, tokens, nested=True): if state == 'value' and token == '!': state = 'bang' bang_position = i - elif state == 'bang' and token.type == 'ident' \ - and token.lower_value == 'important': + elif (state == 'bang' and token.type == 'ident' + and token.lower_value == 'important'): state = 'important' elif token.type not in ('whitespace', 'comment'): state = 'value' @@ -161,8 +161,9 @@ def _parse_declaration(first_token, tokens, nested=True): # TODO: Handle unicode-range - return Declaration(name.source_line, name.source_column, name.value, - name.lower_value, value, state == 'important') + return Declaration( + name.source_line, name.source_column, name.value, name.lower_value, + value, state == 'important') def _consume_blocks_content(first_token, tokens): @@ -183,8 +184,7 @@ def _consume_blocks_content(first_token, tokens): return declaration else: tokens = chain(declaration_tokens, semicolon_token, tokens) - return _consume_qualified_rule( - first_token, tokens, stop_token=';', nested=True) + return _consume_qualified_rule(first_token, tokens, stop_token=';', nested=True) def _consume_declaration_in_list(first_token, tokens): @@ -478,8 +478,9 @@ def _consume_at_rule(at_keyword, tokens): elif token == ';': break prelude.append(token) - return AtRule(at_keyword.source_line, at_keyword.source_column, - at_keyword.value, at_keyword.lower_value, prelude, content) + return AtRule( + at_keyword.source_line, at_keyword.source_column, at_keyword.value, + at_keyword.lower_value, prelude, content) def _rule_error(token, name): @@ -523,5 +524,5 @@ def _consume_qualified_rule(first_token, tokens, nested=False, prelude.append(token) else: return _rule_error(prelude[-1], 'EOF') - return QualifiedRule(first_token.source_line, first_token.source_column, - prelude, block.content) + return QualifiedRule( + first_token.source_line, first_token.source_column, prelude, block.content) diff --git a/tinycss2/serializer.py b/tinycss2/serializer.py index 819b1b0..b501216 100644 --- a/tinycss2/serializer.py +++ b/tinycss2/serializer.py @@ -121,8 +121,7 @@ def _serialize_to(nodes, write): BAD_PAIRS = set( [(a, b) - for a in ('ident', 'at-keyword', 'hash', 'dimension', '#', '-', - 'number') + for a in ('ident', 'at-keyword', 'hash', 'dimension', '#', '-', 'number') for b in ('ident', 'function', 'url', 'number', 'percentage', 'dimension', 'unicode-range')] + [(a, b) diff --git a/tinycss2/tokenizer.py b/tinycss2/tokenizer.py index 30ccd14..08af8af 100644 --- a/tinycss2/tokenizer.py +++ b/tinycss2/tokenizer.py @@ -3,11 +3,11 @@ from webencodings import ascii_lower -from .ast import ( +from .ast import ( # isort: skip AtKeywordToken, Comment, CurlyBracketsBlock, DimensionToken, FunctionBlock, - HashToken, IdentToken, LiteralToken, NumberToken, ParenthesesBlock, - ParseError, PercentageToken, SquareBracketsBlock, StringToken, - UnicodeRangeToken, URLToken, WhitespaceToken) + HashToken, IdentToken, LiteralToken, NumberToken, ParenthesesBlock, ParseError, + PercentageToken, SquareBracketsBlock, StringToken, UnicodeRangeToken, URLToken, + WhitespaceToken) from .serializer import serialize_string_value, serialize_url _NUMBER_RE = re.compile(r'[-+]?([0-9]*\.)?[0-9]+([eE][+-]?[0-9]+)?') @@ -108,11 +108,9 @@ def parse_component_value_list(css, skip_comments=False): line, column, value, int_value, repr_, unit)) elif css.startswith('%', pos): pos += 1 - tokens.append(PercentageToken( - line, column, value, int_value, repr_)) + tokens.append(PercentageToken(line, column, value, int_value, repr_)) else: - tokens.append(NumberToken( - line, column, value, int_value, repr_)) + tokens.append(NumberToken(line, column, value, int_value, repr_)) elif c == '@': pos += 1 if pos < length and _is_ident_start(css, pos): @@ -175,12 +173,10 @@ def parse_component_value_list(css, skip_comments=False): pos = css.find('*/', pos + 2) if pos == -1: if not skip_comments: - tokens.append( - Comment(line, column, css[token_start_pos + 2:])) + tokens.append(Comment(line, column, css[token_start_pos + 2:])) break if not skip_comments: - tokens.append( - Comment(line, column, css[token_start_pos + 2:pos])) + tokens.append(Comment(line, column, css[token_start_pos + 2:pos])) pos += 2 elif css.startswith('