diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..59ae75c --- /dev/null +++ b/codecov.yml @@ -0,0 +1,13 @@ +# https://docs.codecov.io/docs/common-recipe-list +# https://docs.codecov.io/docs/commit-status#patch-status + +coverage: + status: + + project: + default: + target: 90% + + patch: + default: + informational: true diff --git a/cratedb_sqlparse_py/cratedb_sqlparse/__init__.py b/cratedb_sqlparse_py/cratedb_sqlparse/__init__.py index d1ba64b..c9b943b 100644 --- a/cratedb_sqlparse_py/cratedb_sqlparse/__init__.py +++ b/cratedb_sqlparse_py/cratedb_sqlparse/__init__.py @@ -1,4 +1,3 @@ -from .parser import sqlparse, ParsingException - -__all__ = ['sqlparse', 'ParsingException'] +from .parser import ParsingException, sqlparse +__all__ = ["sqlparse", "ParsingException"] diff --git a/cratedb_sqlparse_py/cratedb_sqlparse/generated_parser/AbstractSqlBaseLexer.py b/cratedb_sqlparse_py/cratedb_sqlparse/generated_parser/AbstractSqlBaseLexer.py index 3422eb4..e3282d2 100644 --- a/cratedb_sqlparse_py/cratedb_sqlparse/generated_parser/AbstractSqlBaseLexer.py +++ b/cratedb_sqlparse_py/cratedb_sqlparse/generated_parser/AbstractSqlBaseLexer.py @@ -3,8 +3,11 @@ class AbstractSqlBaseLexer(Lexer): """ - Automatically generated by Antlr4. It was added originally in CrateDB (https://github.com/crate/crate/commit/8e7cfd7c4a05fc27de8ce71af9165b98c986d883) - to implement $ strings, e.g: "SELECT $my friend's house$", we cannot do the same since it also generates invalid python syntax: + Automatically generated by Antlr4. + + It was added originally in CrateDB (https://github.com/crate/crate/commit/8e7cfd7c4a05fc27de8ce71af9165b98c986d883) + to implement $ strings, e.g: "SELECT $my friend's house$", we cannot do the same since it also generates invalid + Python syntax: # SqlBaseLexer.py class SqlBaseLexer(AbstractSqlBaseLexer): diff --git a/cratedb_sqlparse_py/cratedb_sqlparse/parser.py b/cratedb_sqlparse_py/cratedb_sqlparse/parser.py index 875511d..a272f07 100644 --- a/cratedb_sqlparse_py/cratedb_sqlparse/parser.py +++ b/cratedb_sqlparse_py/cratedb_sqlparse/parser.py @@ -1,10 +1,10 @@ from typing import List -from antlr4 import InputStream, CommonTokenStream, Token +from antlr4 import CommonTokenStream, InputStream, Token from antlr4.error.ErrorListener import ErrorListener -from cratedb_sqlparse.generated_parser.SqlBaseParser import SqlBaseParser from cratedb_sqlparse.generated_parser.SqlBaseLexer import SqlBaseLexer +from cratedb_sqlparse.generated_parser.SqlBaseParser import SqlBaseParser def BEGIN_DOLLAR_QUOTED_STRING_action(self, localctx, actionIndex): @@ -17,9 +17,10 @@ def END_DOLLAR_QUOTED_STRING_action(self, localctx, actionIndex): self.tags.pop() -def END_DOLLAR_QUOTED_STRING_sempred(self, localctx, predIndex): +def END_DOLLAR_QUOTED_STRING_sempred(self, localctx, predIndex) -> bool: if predIndex == 0: return self.tags[0] == self.text + return False SqlBaseLexer.tags = [] @@ -46,7 +47,7 @@ class ExceptionErrorListener(ErrorListener): """ def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): - raise ParsingException(f'line{line}:{column} {msg}') + raise ParsingException(f"line{line}:{column} {msg}") class Statement: @@ -76,10 +77,7 @@ def query(self) -> str: """ Returns the query, comments and ';' are not included. """ - return self.ctx.parser.getTokenStream().getText( - start=self.ctx.start.tokenIndex, - stop=self.ctx.stop.tokenIndex - ) + return self.ctx.parser.getTokenStream().getText(start=self.ctx.start.tokenIndex, stop=self.ctx.stop.tokenIndex) @property def type(self): @@ -96,8 +94,8 @@ def sqlparse(query: str) -> List[Statement]: """ Parses a string into SQL `Statement`. """ - input = CaseInsensitiveStream(query) - lexer = SqlBaseLexer(input) + input_ = CaseInsensitiveStream(query) + lexer = SqlBaseLexer(input_) lexer.removeErrorListeners() stream = CommonTokenStream(lexer) @@ -109,8 +107,6 @@ def sqlparse(query: str) -> List[Statement]: # At this point, all errors are already raised; it's seasonably safe to assume # that the statements are valid. - statements = list(filter( - lambda children: isinstance(children, SqlBaseParser.StatementContext), tree.children - )) + statements = list(filter(lambda children: isinstance(children, SqlBaseParser.StatementContext), tree.children)) return [Statement(statement) for statement in statements] diff --git a/cratedb_sqlparse_py/pyproject.toml b/cratedb_sqlparse_py/pyproject.toml index eb56846..c5c6a20 100644 --- a/cratedb_sqlparse_py/pyproject.toml +++ b/cratedb_sqlparse_py/pyproject.toml @@ -116,6 +116,12 @@ install_types = true ignore_missing_imports = true implicit_optional = true non_interactive = true +# FIXME: Does not work? +exclude = [ + "^SqlBaseLexer\\.py$", + "cratedb_sqlparse/generated_parser/", + "cratedb_sqlparse/generated_parser/SqlBaseParser.py", +] [tool.pytest.ini_options] addopts = """ @@ -197,17 +203,17 @@ check = [ ] format = [ - # { cmd = "ruff format ." }, + { cmd = "ruff format ." }, # Configure Ruff not to auto-fix (remove!) unused variables (F841) and `print` statements (T201). - # { cmd = "ruff check --fix --ignore=ERA --ignore=F401 --ignore=F841 --ignore=T20 ." }, + { cmd = "ruff check --fix --ignore=ERA --ignore=F401 --ignore=F841 --ignore=T20 ." }, { cmd = "pyproject-fmt --keep-full-version pyproject.toml" }, ] lint = [ - # { cmd = "ruff format --check ." }, - # { cmd = "ruff check ." }, + { cmd = "ruff format --check ." }, + { cmd = "ruff check ." }, { cmd = "validate-pyproject pyproject.toml" }, - # { cmd = "mypy" }, + # { cmd = "mypy ." }, ] release = [ diff --git a/cratedb_sqlparse_py/tests/conftest.py b/cratedb_sqlparse_py/tests/conftest.py index 3d5d40f..fcddbce 100644 --- a/cratedb_sqlparse_py/tests/conftest.py +++ b/cratedb_sqlparse_py/tests/conftest.py @@ -1,10 +1,10 @@ import subprocess import sys +from importlib.util import find_spec from pathlib import Path import pytest - HERE = Path(__file__).parent PROJECT_ROOT = HERE.parent.parent SETUP_GRAMMAR = PROJECT_ROOT / "setup_grammar.py" @@ -16,11 +16,13 @@ def generate(): Pytest fixture to generate runtime grammar from grammar description. """ try: - import cratedb_sqlparse.generated_parser.SqlBaseParser + # Test module for availability. + find_spec("cratedb_sqlparse.generated_parser.SqlBaseParser") except ImportError: - subprocess.check_call([sys.executable, SETUP_GRAMMAR], cwd=HERE.parent.parent) + subprocess.check_call([sys.executable, SETUP_GRAMMAR], cwd=HERE.parent.parent) # noqa: S603 try: - import cratedb_sqlparse.generated_parser.SqlBaseParser - except ImportError: - raise RuntimeError("Python grammar has not been generated") + # Test module for availability. + find_spec("cratedb_sqlparse.generated_parser.SqlBaseParser") + except ImportError as ex: + raise RuntimeError("Python grammar has not been generated") from ex diff --git a/cratedb_sqlparse_py/tests/test_lexer.py b/cratedb_sqlparse_py/tests/test_lexer.py index 427df73..a69588e 100644 --- a/cratedb_sqlparse_py/tests/test_lexer.py +++ b/cratedb_sqlparse_py/tests/test_lexer.py @@ -3,20 +3,22 @@ def test_sqlparser_one_statement(query=None): from cratedb_sqlparse import sqlparse - query = query or 'SELECT 1;' + + query = query or "SELECT 1;" r = sqlparse(query) assert len(r) == 1 stmt = r[0] - assert stmt.query == query.replace(';', '') # obj.query doesn't include comments or ';' + assert stmt.query == query.replace(";", "") # obj.query doesn't include comments or ';' assert stmt.original_query == query - assert stmt.type == 'SELECT' + assert stmt.type == "SELECT" def test_sqlparse_several_statements(): from cratedb_sqlparse import sqlparse + query = """ SELECT 1; INSERT INTO doc.tbl VALUES (1,2,3,4,5,6); @@ -29,12 +31,13 @@ def test_sqlparse_several_statements(): test_sqlparser_one_statement(r[0].query) - assert r[1].type == 'INSERT' - assert r[2].type == 'SELECT' + assert r[1].type == "INSERT" + assert r[2].type == "SELECT" def test_sqlparse_dollar_string(): from cratedb_sqlparse import sqlparse + query = "update test set a=$$test;test$$" r = sqlparse(query) @@ -42,7 +45,8 @@ def test_sqlparse_dollar_string(): def test_sqlparse_raises_exception(): - from cratedb_sqlparse import sqlparse, ParsingException + from cratedb_sqlparse import ParsingException, sqlparse + query = "SALUT MON AMIE" with pytest.raises(ParsingException): @@ -51,6 +55,7 @@ def test_sqlparse_raises_exception(): def test_sqlparse_is_case_insensitive(): from cratedb_sqlparse import sqlparse + query = "inSerT InTo doc.Tbl1 Values (1)" r = sqlparse(query)