lexcql-parser 1.3.2__tar.gz → 1.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lexcql-parser
3
- Version: 1.3.2
3
+ Version: 1.3.4
4
4
  Summary: LexCQL Query Grammar and Parser
5
5
  Keywords: LexCQL,FCS,CQL,Query Parser
6
6
  Author: Erik Körner
@@ -25,6 +25,8 @@ Requires-Dist: twine>=6.2.0 ; extra == 'build'
25
25
  Requires-Dist: black>=26.1.0 ; extra == 'style'
26
26
  Requires-Dist: flake8>=7.3.0 ; extra == 'style'
27
27
  Requires-Dist: isort>=8.0.0 ; extra == 'style'
28
+ Requires-Dist: mypy>=1.19.1 ; extra == 'style'
29
+ Requires-Dist: types-antlr4-python3-runtime>=4.13.0.20251118 ; extra == 'style'
28
30
  Requires-Dist: pytest>=9.0.2 ; extra == 'test'
29
31
  Requires-Dist: pytest-clarity>=1.0.1 ; extra == 'test'
30
32
  Requires-Dist: pytest-cov>=7.0.0 ; extra == 'test'
@@ -175,6 +177,8 @@ uv sync --extra style
175
177
  uv run isort --check --diff .
176
178
  uv run black --check .
177
179
  uv run flake8 . --show-source --statistics
180
+
181
+ uv run mypy src
178
182
  ```
179
183
 
180
184
  Run tests:
@@ -135,6 +135,8 @@ uv sync --extra style
135
135
  uv run isort --check --diff .
136
136
  uv run black --check .
137
137
  uv run flake8 . --show-source --statistics
138
+
139
+ uv run mypy src
138
140
  ```
139
141
 
140
142
  Run tests:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lexcql-parser"
3
- version = "1.3.2"
3
+ version = "1.3.4"
4
4
  description = "LexCQL Query Grammar and Parser"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -51,6 +51,8 @@ style = [
51
51
  "black>=26.1.0",
52
52
  "flake8>=7.3.0",
53
53
  "isort>=8.0.0",
54
+ "mypy>=1.19.1",
55
+ "types-antlr4-python3-runtime>=4.13.0.20251118",
54
56
  ]
55
57
  build = [
56
58
  "twine>=6.2.0",
@@ -87,3 +89,22 @@ skip = [
87
89
  "src/lexcql/LexParserVisitor.py",
88
90
  ]
89
91
  skip_gitignore = true
92
+
93
+ # ignore all auto-generated antlr4 files,
94
+ # it needs a lot of work to quieten all warnings
95
+ [tool.mypy]
96
+ exclude = [
97
+ 'LexLexer\.py$',
98
+ 'LexParser\.py$',
99
+ 'LexParserListener\.py$',
100
+ 'LexParserVisitor\.py$',
101
+ ]
102
+ check_untyped_defs = true
103
+
104
+ [[tool.mypy.overrides]]
105
+ module = [
106
+ "antlr4",
107
+ "antlr4.error",
108
+ "antlr4.error.ErrorListener",
109
+ ]
110
+ ignore_missing_imports = true
@@ -94,12 +94,12 @@ class QueryVisitor(Generic[_R], metaclass=ABCMeta):
94
94
  if not node:
95
95
  return None
96
96
 
97
- def noop(node: "QueryNode") -> Optional[_R]:
98
- return self.defaultResult()
99
-
100
97
  # search for specific visit function based on node_type
101
98
  method_name = f"visit_{node.node_type}"
102
- method = getattr(self, method_name, noop)
99
+ method = getattr(self, method_name, self.visitChildren)
100
+
101
+ if LOGGER.isEnabledFor(logging.DEBUG):
102
+ LOGGER.debug("visiting '%s()': %s", method.__name__, node)
103
103
 
104
104
  return method(node)
105
105
 
@@ -137,7 +137,7 @@ class QueryVisitorAdapter(QueryVisitor[_R]):
137
137
  Generic with regards to the return type of the visit operation.
138
138
  """
139
139
 
140
- def visit_SearchClauseGroup(self, node: "SearchClauseGroup") -> _R:
140
+ def visit_SearchClauseGroup(self, node: "SearchClauseGroup") -> Optional[_R]:
141
141
  """Visit a *search_clause_group* query node.
142
142
 
143
143
  Args:
@@ -148,7 +148,7 @@ class QueryVisitorAdapter(QueryVisitor[_R]):
148
148
  """
149
149
  return self.visitChildren(node)
150
150
 
151
- def visit_Subquery(self, node: "Subquery") -> _R:
151
+ def visit_Subquery(self, node: "Subquery") -> Optional[_R]:
152
152
  """Visit a *subquery* query node.
153
153
 
154
154
  Args:
@@ -159,7 +159,7 @@ class QueryVisitorAdapter(QueryVisitor[_R]):
159
159
  """
160
160
  return self.visitChildren(node)
161
161
 
162
- def visit_SearchClause(self, node: "SearchClause") -> _R:
162
+ def visit_SearchClause(self, node: "SearchClause") -> Optional[_R]:
163
163
  """Visit a *search_clause* query node.
164
164
 
165
165
  Args:
@@ -170,7 +170,7 @@ class QueryVisitorAdapter(QueryVisitor[_R]):
170
170
  """
171
171
  return self.visitChildren(node)
172
172
 
173
- def visit_Relation(self, node: "Relation") -> _R:
173
+ def visit_Relation(self, node: "Relation") -> Optional[_R]:
174
174
  """Visit a *relation* query node.
175
175
 
176
176
  Args:
@@ -181,7 +181,7 @@ class QueryVisitorAdapter(QueryVisitor[_R]):
181
181
  """
182
182
  return self.visitChildren(node)
183
183
 
184
- def visit_Modifier(self, node: "Modifier") -> _R:
184
+ def visit_Modifier(self, node: "Modifier") -> Optional[_R]:
185
185
  """Visit a *modifier* query node.
186
186
 
187
187
  Args:
@@ -361,7 +361,7 @@ class QueryNode(Generic[_R], metaclass=ABCMeta):
361
361
  strrepr += f"@{self.location.start}:{self.location.stop}"
362
362
  return strrepr
363
363
 
364
- def accept(self, visitor: QueryVisitor) -> _R:
364
+ def accept(self, visitor: QueryVisitor) -> Optional[_R]:
365
365
  return visitor.visit(self)
366
366
 
367
367
 
@@ -411,7 +411,7 @@ class Relation(QueryNode):
411
411
  relation: the relation name or symbol
412
412
  modifiers: the list of modifiers for this relation or ``None``
413
413
  """
414
- super().__init__(QueryNodeType.RELATION, children=modifiers)
414
+ super().__init__(QueryNodeType.RELATION, children=modifiers) # type: ignore
415
415
 
416
416
  self.relation = relation
417
417
  """the relation"""
@@ -422,7 +422,7 @@ class Relation(QueryNode):
422
422
  Returns:
423
423
  List[Modifier]: the modifiers
424
424
  """
425
- return self.children
425
+ return self.children # type: ignore
426
426
 
427
427
  @property
428
428
  def modifiers(self) -> List[Modifier]:
@@ -465,7 +465,7 @@ class SearchClause(QueryNode):
465
465
  Returns:
466
466
  Optional[Relation]: the relation or ``None``
467
467
  """
468
- return self.get_child(0, Relation)
468
+ return self.get_child(0, Relation) # type: ignore
469
469
 
470
470
  @property
471
471
  def relation(self) -> Optional[Relation]:
@@ -542,7 +542,7 @@ class SearchClauseGroup(QueryNode):
542
542
  return self.get_right_child()
543
543
 
544
544
  @property
545
- def boolean(self) -> QueryNode:
545
+ def boolean(self) -> RBoolean:
546
546
  return self.get_boolean()
547
547
 
548
548
  def has_boolean(self, r_boolean: RBoolean) -> bool:
@@ -586,7 +586,7 @@ class Subquery(QueryNode):
586
586
  self.inParentheses = inParentheses
587
587
  """Is this query node in parentheses."""
588
588
 
589
- def get_child(self) -> QueryNode:
589
+ def get_child(self) -> QueryNode: # type: ignore
590
590
  """Get the inner child
591
591
 
592
592
  Returns:
@@ -754,18 +754,22 @@ class ExpressionTreeBuilder(LexParserVisitor):
754
754
  if len(self.stack) > pos:
755
755
  if len(self.stack) - pos == 1:
756
756
  # TODO: noop?
757
- node: QueryNode = self.stack.pop()
757
+ node = self.stack.pop()
758
+ assert isinstance(node, QueryNode), f"node must be a QueryNode, found {node=}"
758
759
  self.stack.append(node)
759
760
  else:
760
- children: List[QueryNode] = []
761
+ children: List[QueryNode | RBoolean] = []
761
762
  while len(self.stack) > pos:
762
763
  children.insert(0, self.stack.pop())
763
764
 
764
765
  # build tree
765
- node: QueryNode = children.pop(0)
766
+ node = children.pop(0)
767
+ assert isinstance(node, QueryNode), f"node must be a QueryNode, found {node=}"
766
768
  while len(children) >= 2:
767
- rBoolean: RBoolean = children.pop(0)
768
- other: QueryNode = children.pop(0)
769
+ rBoolean = children.pop(0)
770
+ assert isinstance(rBoolean, RBoolean), f"node must be a RBoolean, found {rBoolean=}"
771
+ other = children.pop(0)
772
+ assert isinstance(other, QueryNode), f"node must be a QueryNode, found {other=}"
769
773
  node = SearchClauseGroup(node, rBoolean, other)
770
774
  if self.parser.enableSourceLocations:
771
775
  node.location = SourceLocation.fromContext(ctx)
@@ -872,11 +876,11 @@ class ExpressionTreeBuilder(LexParserVisitor):
872
876
 
873
877
  searchTerm: str
874
878
  if ctx.SIMPLE_STRING() is not None:
875
- tn: TerminalNodeImpl = ctx.SIMPLE_STRING()
879
+ tn = ctx.SIMPLE_STRING()
876
880
  assert isinstance(tn, TerminalNodeImpl), "visitSearch_term ctx.SIMPLE_STRING() must be TerminalNodeImpl"
877
881
  searchTerm = tn.getSymbol().text
878
882
  elif ctx.QUOTED_STRING() is not None:
879
- tn: TerminalNodeImpl = ctx.QUOTED_STRING()
883
+ tn = ctx.QUOTED_STRING()
880
884
  assert isinstance(tn, TerminalNodeImpl), "visitSearch_term ctx.QUOTED_STRING() must be TerminalNodeImpl"
881
885
  searchTerm = tn.getSymbol().text
882
886
  searchTerm = self.unquoteString(searchTerm)
@@ -919,7 +923,7 @@ class ExpressionTreeBuilder(LexParserVisitor):
919
923
  m_ctx = ctx.modifier_list()
920
924
  modifiers: List[Modifier] = []
921
925
  if m_ctx is not None:
922
- modifiers: List[Modifier] = self.stack.pop()
926
+ modifiers = self.stack.pop()
923
927
 
924
928
  name: str = self.stack.pop()
925
929
 
@@ -980,7 +984,7 @@ class ExpressionTreeBuilder(LexParserVisitor):
980
984
  ctx.getText(),
981
985
  )
982
986
 
983
- tn: TerminalNodeImpl = ctx.modifier_name().simple_name().SIMPLE_STRING()
987
+ tn = ctx.modifier_name().simple_name().SIMPLE_STRING()
984
988
  assert isinstance(
985
989
  tn, TerminalNodeImpl
986
990
  ), "visitModifier ctx.modifier_name().simple_name().SIMPLE_STRING() must be TerminalNodeImpl"
@@ -991,7 +995,7 @@ class ExpressionTreeBuilder(LexParserVisitor):
991
995
  r_ctx = ctx.modifier_relation()
992
996
  if r_ctx is not None:
993
997
  relation = r_ctx.relation_symbol().getText()
994
- tn: TerminalNodeImpl = r_ctx.modifier_value().SIMPLE_STRING()
998
+ tn = r_ctx.modifier_value().SIMPLE_STRING()
995
999
  assert isinstance(
996
1000
  tn, TerminalNodeImpl
997
1001
  ), "visitModifier r_ctx.modifier_value().SIMPLE_STRING() must be TerminalNodeImpl"
@@ -372,7 +372,12 @@ class LexCQLValidatorV0_3(Validator[None]):
372
372
  )
373
373
  else:
374
374
  if index not in self.KNOWN_INDEXES:
375
- self.validation_error(node, f"Unknown index '{node.index}'!")
375
+ if index == "def":
376
+ self.validation_warning(
377
+ node, f"Usage of legacy definition index '{node.index}'. Please update to 'definition'."
378
+ )
379
+ else:
380
+ self.validation_error(node, f"Unknown index '{node.index}'!")
376
381
 
377
382
  # TODO: check `search_term` against relations/modifiers? (regex/masked)
378
383