Skip to content

Commit 28a6c26

Browse files
author
Gerit Wagner
committed
address linter messages
1 parent b8a16fb commit 28a6c26

File tree

10 files changed

+70
-41
lines changed

10 files changed

+70
-41
lines changed

search_query/generic/serializer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def to_string_generic(query: Query) -> str:
1515

1616
result = ""
1717
query_content = query.value
18-
if hasattr(query, "distance") and query.distance:
18+
if hasattr(query, "distance"): # and isinstance(query.distance, int):
1919
query_content += f"/{query.distance}"
2020
if query.search_field:
2121
query_content += f"[{query.search_field}]"

search_query/pubmed/linter.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -228,24 +228,29 @@ def _print_unequal_precedence_warning(self, index: int) -> None:
228228
for idx, op in enumerate(precedence_list):
229229
if idx == 0:
230230
precedence_lines.append(
231-
f"Operator {Colors.GREEN}{op}{Colors.END} at position {idx + 1} is evaluated first "
231+
f"Operator {Colors.GREEN}{op}{Colors.END} "
232+
f"at position {idx + 1} is evaluated first "
232233
f"because it is the leftmost operator."
233234
)
234235
elif idx == len(precedence_list) - 1:
235236
precedence_lines.append(
236-
f"Operator {Colors.ORANGE}{op}{Colors.END} at position {idx + 1} is evaluated last "
237+
f"Operator {Colors.ORANGE}{op}{Colors.END} "
238+
f"at position {idx + 1} is evaluated last "
237239
f"because it is the rightmost operator."
238240
)
239241
else:
240242
precedence_lines.append(
241-
f"Operator {Colors.ORANGE}{op}{Colors.END} at position {idx + 1} is evaluated next."
243+
f"Operator {Colors.ORANGE}{op}{Colors.END} "
244+
f"at position {idx + 1} is evaluated next."
242245
)
243246

244247
precedence_info = "\n".join(precedence_lines)
245248

246249
details = (
247-
"The query uses multiple operators, but without parentheses to make the intended logic explicit. "
248-
"PubMed evaluates queries strictly from left to right without applying traditional operator precedence. "
250+
"The query uses multiple operators, but without parentheses "
251+
"to make the intended logic explicit. "
252+
"PubMed evaluates queries strictly from left to right "
253+
"without applying traditional operator precedence. "
249254
"This can lead to unexpected interpretations of the query.\n\n"
250255
"Specifically:\n"
251256
f"{precedence_info}\n\n"
@@ -410,7 +415,10 @@ def check_invalid_proximity_operator(self) -> None:
410415
search_phrase_token.value[0] == '"'
411416
and search_phrase_token.value[-1] == '"'
412417
):
413-
details = "Proximity search requires 2 or more search terms enclosed in double quotes."
418+
details = (
419+
"Proximity search requires 2 or "
420+
"more search terms enclosed in double quotes."
421+
)
414422
self.add_linter_message(
415423
QueryErrorCode.INVALID_PROXIMITY_USE,
416424
positions=[self.tokens[index - 1].position],

search_query/pubmed/parser.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,9 @@ def _parse_search_term(self, tokens: list) -> Query:
208208
if len(tokens) > 1 and tokens[1].type == TokenTypes.FIELD:
209209
if ":~" in tokens[1].value:
210210
# Parse NEAR query
211-
field_value, prox_value = self.PROXIMITY_REGEX.match(
211+
field_value, distance = self.PROXIMITY_REGEX.match(
212212
tokens[1].value
213-
).groups()
213+
).groups() # type: ignore
214214
field_value = "[" + field_value + "]"
215215
return NEARQuery(
216216
value=Operators.NEAR,
@@ -226,7 +226,9 @@ def _parse_search_term(self, tokens: list) -> Query:
226226
)
227227
],
228228
position=(tokens[0].position[0], tokens[1].position[1]),
229-
distance=prox_value,
229+
# TODO : pass int (ensuring valid NEAR distances)
230+
# or string (preventing errors during parsing)?
231+
distance=distance, # type: ignore
230232
platform="deactivated",
231233
)
232234

search_query/pubmed/serializer.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@ def to_string_pubmed(query: Query) -> str:
2020
if query.value == Operators.NEAR:
2121
# Serialize near query
2222
distance = query.distance if hasattr(query, "distance") else 0
23+
assert query.children[0].search_field
2324
return (
2425
f"{query.children[0].value}"
2526
f"{query.children[0].search_field.value[:-1]}"
2627
f":~{distance}]"
2728
)
2829
if query.value == Operators.RANGE:
2930
# Serialize range query
31+
assert query.children[0].search_field
32+
assert query.children[1]
3033
return (
3134
f"{query.children[0].value}:{query.children[1].value}"
3235
f"{query.children[0].search_field.value}"

search_query/pubmed/translator.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/usr/bin/env python3
22
"""Pubmed query translator."""
3+
import typing
34
from collections import defaultdict
45
from itertools import permutations
56

@@ -119,6 +120,7 @@ def _combine_tiab(cls, query: "Query") -> None:
119120
for child in query.children:
120121
cls._combine_tiab(child)
121122

123+
# pylint: disable=too-many-locals, too-many-branches
122124
@classmethod
123125
def _collapse_near_queries(cls, query: Query) -> Query:
124126
"""Recursively collapse NEAR queries in the query tree."""
@@ -132,11 +134,12 @@ def _collapse_near_queries(cls, query: Query) -> Query:
132134
query.children.pop()
133135
return query
134136

135-
elif query.value == Operators.OR:
137+
if query.value == Operators.OR:
136138
# Extract NEAR queries
137-
near_queries = []
138-
other_queries = []
139+
near_queries: typing.List[Query] = []
140+
other_queries: typing.List[Query] = []
139141
for child in query.children:
142+
# pylint: disable=unidiomatic-typecheck
140143
(near_queries if type(child) is NEARQuery else other_queries).append(
141144
child
142145
)
@@ -152,11 +155,13 @@ def _collapse_near_queries(cls, query: Query) -> Query:
152155

153156
combined_near_queries = []
154157
for distance, queries in grouped_queries.items():
155-
# For each group, extract term pairs from NEAR queries and map them to corresponding fields
158+
# For each group, extract term pairs from NEAR queries and
159+
# map them to corresponding fields
156160
term_field_map = defaultdict(set)
157161
for q in queries:
158162
term_a = q.children[0].value
159163
term_b = q.children[1].value
164+
assert q.children[0].search_field
160165
term_field_map[(min(term_a, term_b), max(term_a, term_b))].add(
161166
q.children[0].search_field.value
162167
)
@@ -175,7 +180,7 @@ def _collapse_near_queries(cls, query: Query) -> Query:
175180
children=[
176181
Term(
177182
value=f'"{term_a} {term_b}"',
178-
search_field=field,
183+
search_field=SearchField(value=field),
179184
platform="deactivated",
180185
)
181186
],
@@ -210,6 +215,7 @@ def translate_search_fields_to_generic(cls, query: Query) -> Query:
210215
if query.children:
211216
if query.value == Operators.NEAR:
212217
# Expand NEAR queries
218+
assert query.children[0].search_field
213219
search_field_set = syntax_str_to_generic_search_field_set(
214220
query.children[0].search_field.value
215221
)
@@ -254,22 +260,25 @@ def _expand_combined_fields(cls, query: Query, search_fields: set) -> Query:
254260
)
255261
)
256262
return OrQuery(
257-
children=query_children,
263+
children=query_children, # type: ignore
258264
search_field=None,
259265
)
260266

261267
@classmethod
262268
def _expand_near_query(cls, query: Query, search_fields: set) -> Query:
263269
"""Expand NEAR query into an OR query"""
264-
if type(query) is not NEARQuery:
270+
if type(query) is not NEARQuery: # pylint: disable=unidiomatic-typecheck
265271
return query
272+
distance = 0
273+
if hasattr(query, "distance"):
274+
distance = int(query.distance) # type: ignore
266275

267-
distance = query.distance if hasattr(query, "distance") else 0
268276
query_children = []
269277
search_terms = query.children[0].value.strip('"').split()
270278
# Handle [tiab] by generating NEAR queries for both 'title' and 'abstract'
271279
for search_field in sorted(list(search_fields)):
272-
# Get all possible ordered pairs of search terms in the proximity search phrase
280+
# Get all possible ordered pairs of search terms
281+
# in the proximity search phrase
273282
pairs = list(permutations(search_terms, 2))
274283
for pair in pairs:
275284
# Create binary near query for each pair
@@ -290,7 +299,7 @@ def _expand_near_query(cls, query: Query, search_fields: set) -> Query:
290299
)
291300
)
292301
return OrQuery(
293-
children=query_children,
302+
children=query_children, # type: ignore
294303
search_field=None,
295304
)
296305

search_query/query.py

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def __init__(
3131
position: typing.Optional[typing.Tuple[int, int]] = None,
3232
platform: str = "generic",
3333
) -> None:
34-
if type(self) is Query:
34+
if type(self) is Query: # pylint: disable=unidiomatic-typecheck
3535
raise TypeError(
3636
"The base Query type cannot be instantiated directly. "
3737
"Use Query.create() or the appropriate query subclass."
@@ -80,6 +80,7 @@ def create(
8080
) -> Query:
8181
"""Factory method for query creation."""
8282
if not operator:
83+
# pylint: disable=import-outside-toplevel
8384
from search_query.query_term import Term
8485

8586
return Term(
@@ -96,33 +97,33 @@ def create(
9697
"platform": platform,
9798
}
9899

100+
# pylint: disable=import-outside-toplevel
99101
if value == Operators.AND:
100102
from search_query.query_and import AndQuery
101103

102-
return AndQuery(**args)
104+
return AndQuery(**args) # type: ignore
103105

104-
elif value == Operators.OR:
106+
if value == Operators.OR:
105107
from search_query.query_or import OrQuery
106108

107-
return OrQuery(**args)
109+
return OrQuery(**args) # type: ignore
108110

109-
elif value == Operators.NOT:
111+
if value == Operators.NOT:
110112
from search_query.query_not import NotQuery
111113

112-
return NotQuery(**args)
114+
return NotQuery(**args) # type: ignore
113115

114-
elif value in {Operators.NEAR, Operators.WITHIN}:
116+
if value in {Operators.NEAR, Operators.WITHIN}:
115117
from search_query.query_near import NEARQuery
116118

117-
return NEARQuery(value=value, distance=distance, **args)
119+
return NEARQuery(value=value, distance=distance, **args) # type: ignore
118120

119-
elif value == Operators.RANGE:
121+
if value == Operators.RANGE:
120122
from search_query.query_range import RangeQuery
121123

122-
return RangeQuery(**args)
124+
return RangeQuery(**args) # type: ignore
123125

124-
else:
125-
raise ValueError(f"Invalid operator value: {value}")
126+
raise ValueError(f"Invalid operator value: {value}")
126127

127128
def _validate_platform_constraints(self) -> None:
128129
if self.platform == "deactivated":
@@ -319,14 +320,17 @@ def search_field(self, sf: typing.Optional[SearchField]) -> None:
319320
"""Set search field property."""
320321
self._search_field = copy.deepcopy(sf) if sf else None
321322

322-
def replace(self, new_query) -> None:
323-
if self.get_parent():
324-
for index, child in enumerate(self.get_parent().children):
323+
def replace(self, new_query: Query) -> None:
324+
"""Replace this query with a new query in the parent's children list."""
325+
parent = self.get_parent()
326+
if parent:
327+
children = parent.children
328+
assert children
329+
for index, child in enumerate(children):
325330
if child is self:
326-
self.get_parent().children[index] = new_query
331+
children[index] = new_query
327332
return
328-
else:
329-
raise RuntimeError("Root node of a query cannot be replaced")
333+
raise RuntimeError("Root node of a query cannot be replaced")
330334

331335
def selects(self, *, record_dict: dict) -> bool:
332336
"""Indicates whether the query selects a given record."""

search_query/query_near.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ def __init__(
5050
platform=platform,
5151
)
5252
self.children = query_children
53+
# assert isinstance(distance, int) and distance >= 0, (
54+
# "distance must be a non-negative integer"
55+
# )
5356
self.distance: int = distance
5457

5558
@property

search_query/query_not.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def __init__(
4949
platform=platform,
5050
)
5151

52-
self.children = query_children
52+
self.children = query_children # type: ignore
5353

5454
@property
5555
def children(self) -> typing.List[Query]:

search_query/serializer_structured.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def to_string_structured(query: Query, *, level: int = 0) -> str:
3636
search_field = f"[{query.search_field}]"
3737

3838
query_value = query.value
39-
if hasattr(query, "distance") and query.distance:
39+
if hasattr(query, "distance"): # and isinstance(query.distance, int):
4040
query_value += f"/{query.distance}"
4141
result = _reindent(f"{query_value} {search_field}", level)
4242

search_query/wos/translator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def _expand_combined_fields(cls, query: Query, search_fields: set) -> None:
5353

5454
query.replace(
5555
OrQuery(
56-
children=query_children,
56+
children=query_children, # type: ignore
5757
)
5858
)
5959

0 commit comments

Comments
 (0)