Skip to content

Commit 7e19658

Browse files
nicolas-gauthier-sonarsourcesonartech
authored andcommitted
SONARPY-3293 Implement support for Cohere Chats in S7693 (#537)
GitOrigin-RevId: 25a32255eb5053302e61df475a5237d5faea984b
1 parent fdfdef8 commit 7e19658

40 files changed

+2190
-988
lines changed

python-checks/src/main/java/org/sonar/python/checks/utils/CheckUtils.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.sonar.python.checks.utils;
1818

1919
import java.util.List;
20+
import java.util.Optional;
2021
import javax.annotation.CheckForNull;
2122
import javax.annotation.Nullable;
2223
import org.sonar.plugins.python.api.symbols.Symbol;
@@ -34,6 +35,7 @@
3435
import org.sonar.plugins.python.api.tree.ParameterList;
3536
import org.sonar.plugins.python.api.tree.SetLiteral;
3637
import org.sonar.plugins.python.api.tree.Statement;
38+
import org.sonar.plugins.python.api.tree.StringLiteral;
3739
import org.sonar.plugins.python.api.tree.Tree;
3840
import org.sonar.plugins.python.api.tree.Tuple;
3941
import org.sonar.plugins.python.api.types.BuiltinTypes;
@@ -122,6 +124,26 @@ private static boolean calleeHasNameLocals(CallExpression callExpression) {
122124
return callee.is(Tree.Kind.NAME) && "locals".equals(((Name) callee).name());
123125
}
124126

127+
public static boolean hasStringLiteralValue(Expression expression, String value) {
128+
return extractStringLiteral(expression)
129+
.map(StringLiteral::trimmedQuotesValue)
130+
.filter(value::equals)
131+
.isPresent();
132+
}
133+
134+
public static Optional<StringLiteral> extractStringLiteral(Tree tree) {
135+
if (tree.is(STRING_LITERAL)) {
136+
return Optional.of((StringLiteral) tree);
137+
}
138+
if (tree.is(NAME)) {
139+
Expression assignedValue = Expressions.singleAssignedValue(((Name) tree));
140+
if (assignedValue != null && assignedValue.is(STRING_LITERAL)) {
141+
return Optional.of((StringLiteral) assignedValue);
142+
}
143+
}
144+
return Optional.empty();
145+
}
146+
125147
public static boolean isConstant(Expression condition) {
126148
return isImmutableConstant(condition) || isConstantCollectionLiteral(condition);
127149
}

python-checks/src/test/java/org/sonar/python/checks/utils/CheckUtilsTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,13 @@
2626
import java.util.Scanner;
2727
import javax.annotation.Nullable;
2828
import org.junit.jupiter.api.Test;
29+
import org.sonar.plugins.python.api.tree.AssignmentStatement;
2930
import org.sonar.plugins.python.api.tree.ClassDef;
31+
import org.sonar.plugins.python.api.tree.ExpressionStatement;
3032
import org.sonar.plugins.python.api.tree.FileInput;
3133
import org.sonar.plugins.python.api.tree.FunctionDef;
3234
import org.sonar.plugins.python.api.tree.ReturnStatement;
35+
import org.sonar.plugins.python.api.tree.Statement;
3336
import org.sonar.plugins.python.api.tree.Tree;
3437
import org.sonar.python.TestPythonVisitorRunner;
3538
import org.sonar.python.parser.PythonParser;
@@ -168,6 +171,29 @@ void mustBeAProtocolLikeTest() {
168171
});
169172
}
170173

174+
@Test
175+
void hasStringLiteralValueTest() {
176+
var fileInput = parseFileWithSymbols("src/test/resources/checks/checkUtils/hasStringLiteralValueTest.py");
177+
List<Statement> statements = fileInput.statements().statements();
178+
assertThat(statements.get(0)).isInstanceOfSatisfying(AssignmentStatement.class, assignmentStatement -> {
179+
assertThat(CheckUtils.hasStringLiteralValue(assignmentStatement.assignedValue(), "hello")).isTrue();
180+
assertThat(CheckUtils.hasStringLiteralValue(assignmentStatement.assignedValue(), "world")).isFalse();
181+
});
182+
assertThat(statements.get(1)).isInstanceOfSatisfying(ExpressionStatement.class, expressionStatement -> {
183+
assertThat(CheckUtils.hasStringLiteralValue(expressionStatement.expressions().get(0), "hello")).isTrue();
184+
assertThat(CheckUtils.hasStringLiteralValue(expressionStatement.expressions().get(0), "world")).isFalse();
185+
});
186+
assertThat(statements.get(3)).isInstanceOfSatisfying(ExpressionStatement.class, assignmentStatement -> {
187+
assertThat(CheckUtils.hasStringLiteralValue(assignmentStatement.expressions().get(0), "hello")).isFalse();
188+
});
189+
assertThat(statements.get(4)).isInstanceOfSatisfying(ExpressionStatement.class, expressionStatement -> {
190+
assertThat(CheckUtils.hasStringLiteralValue(expressionStatement.expressions().get(0), "anything")).isFalse();
191+
});
192+
assertThat(statements.get(5)).isInstanceOfSatisfying(ExpressionStatement.class, expressionStatement -> {
193+
assertThat(CheckUtils.hasStringLiteralValue(expressionStatement.expressions().get(0), "anything")).isFalse();
194+
});
195+
}
196+
171197
@Test
172198
void isAbstractTest() throws IOException {
173199
var fileInput = parseFile("src/test/resources/checks/checkUtils/isAbstractTest.py");
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
value = 'hello'
2+
value
3+
assignFromVar = value
4+
assignFromVar
5+
unknownVar
6+
unknownCall()

python-frontend/src/main/resources/org/sonar/python/types/custom_protobuf/cohere.client.protobuf

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
2+
cohere.client�3
3+
Clientcohere.client.Client"*SonarPythonAnalyzerFakeStub.CustomStubBase*�
4+
__init__cohere.client.Client.__init__"
5+
None*6
6+
self,
7+
cohere.client.Client"cohere.client.Client*�
8+
api_key�
9+
8Union[builtins.str,CallableType[builtins.function],None]
10+
builtins.str" builtins.strK
11+
CallableType[builtins.function]&
12+
builtins.function"builtins.function
13+
None *T
14+
base_urlD
15+
Union[builtins.str,None]
16+
builtins.str" builtins.str
17+
None *
18+
environment
19+
Any *W
20+
client_nameD
21+
Union[builtins.str,None]
22+
builtins.str" builtins.str
23+
None *Y
24+
timeoutJ
25+
Union[builtins.float,None]
26+
builtins.float"builtins.float
27+
None *:
28+
httpx_client&
29+
Union[Any,None]
30+
Any
31+
None *x
32+
thread_pool_executor\
33+
,concurrent.futures.thread.ThreadPoolExecutor",concurrent.futures.thread.ThreadPoolExecutor *G
34+
!log_warning_experimental_features
35+
builtins.bool"builtins.bool *�
36+
chatcohere.client.Client.chat"
37+
Any*6
38+
self,
39+
cohere.client.Client"cohere.client.Client*)
40+
message
41+
builtins.str" builtins.str*w
42+
acceptsh
43+
!Union[Literal[builtins.str],None]7
44+
Literal[builtins.str] 
45+
builtins.str" builtins.str
46+
None *Q
47+
modelD
48+
Union[builtins.str,None]
49+
builtins.str" builtins.str
50+
None *T
51+
preambleD
52+
Union[builtins.str,None]
53+
builtins.str" builtins.str
54+
None *t
55+
chat_history`
56+
Union[typing.Sequence[Any],None]0
57+
typing.Sequence[Any]
58+
Any"typing.Sequence
59+
None *[
60+
conversation_idD
61+
Union[builtins.str,None]
62+
builtins.str" builtins.str
63+
None *?
64+
prompt_truncation&
65+
Union[Any,None]
66+
Any
67+
None *r
68+
69+
connectors`
70+
Union[typing.Sequence[Any],None]0
71+
typing.Sequence[Any]
72+
Any"typing.Sequence
73+
None *b
74+
search_queries_onlyG
75+
Union[builtins.bool,None]
76+
builtins.bool"builtins.bool
77+
None *q
78+
documents`
79+
Union[typing.Sequence[Any],None]0
80+
typing.Sequence[Any]
81+
Any"typing.Sequence
82+
None *>
83+
citation_quality&
84+
Union[Any,None]
85+
Any
86+
None *]
87+
temperatureJ
88+
Union[builtins.float,None]
89+
builtins.float"builtins.float
90+
None *V
91+
92+
max_tokensD
93+
Union[builtins.int,None]
94+
builtins.int" builtins.int
95+
None *\
96+
max_input_tokensD
97+
Union[builtins.int,None]
98+
builtins.int" builtins.int
99+
None *M
100+
kD
101+
Union[builtins.int,None]
102+
builtins.int" builtins.int
103+
None *S
104+
pJ
105+
Union[builtins.float,None]
106+
builtins.float"builtins.float
107+
None *P
108+
seedD
109+
Union[builtins.int,None]
110+
builtins.int" builtins.int
111+
None *�
112+
stop_sequences�
113+
)Union[typing.Sequence[builtins.str],None]N
114+
typing.Sequence[builtins.str]
115+
builtins.str" builtins.str"typing.Sequence
116+
None *c
117+
frequency_penaltyJ
118+
Union[builtins.float,None]
119+
builtins.float"builtins.float
120+
None *b
121+
presence_penaltyJ
122+
Union[builtins.float,None]
123+
builtins.float"builtins.float
124+
None *\
125+
raw_promptingG
126+
Union[builtins.bool,None]
127+
builtins.bool"builtins.bool
128+
None *m
129+
tools`
130+
Union[typing.Sequence[Any],None]0
131+
typing.Sequence[Any]
132+
Any"typing.Sequence
133+
None *t
134+
tool_results`
135+
Union[typing.Sequence[Any],None]0
136+
typing.Sequence[Any]
137+
Any"typing.Sequence
138+
None *`
139+
force_single_stepG
140+
Union[builtins.bool,None]
141+
builtins.bool"builtins.bool
142+
None *=
143+
response_format&
144+
Union[Any,None]
145+
Any
146+
None *�
147+
safety_mode�
148+
QUnion[Literal[builtins.str],Literal[builtins.str],Literal[builtins.str],None,Any]7
149+
Literal[builtins.str] 
150+
builtins.str" builtins.str7
151+
Literal[builtins.str] 
152+
builtins.str" builtins.str7
153+
Literal[builtins.str] 
154+
builtins.str" builtins.str
155+
None
156+
Any *=
157+
request_options&
158+
Union[Any,None]
159+
Any
160+
None *�
161+
chat_stream cohere.client.Client.chat_stream"0
162+
typing.Iterator[Any]
163+
Any"typing.Iterator*6
164+
self,
165+
cohere.client.Client"cohere.client.Client*)
166+
message
167+
builtins.str" builtins.str*w
168+
acceptsh
169+
!Union[Literal[builtins.str],None]7
170+
Literal[builtins.str] 
171+
builtins.str" builtins.str
172+
None *Q
173+
modelD
174+
Union[builtins.str,None]
175+
builtins.str" builtins.str
176+
None *T
177+
preambleD
178+
Union[builtins.str,None]
179+
builtins.str" builtins.str
180+
None *t
181+
chat_history`
182+
Union[typing.Sequence[Any],None]0
183+
typing.Sequence[Any]
184+
Any"typing.Sequence
185+
None *[
186+
conversation_idD
187+
Union[builtins.str,None]
188+
builtins.str" builtins.str
189+
None *?
190+
prompt_truncation&
191+
Union[Any,None]
192+
Any
193+
None *r
194+
195+
connectors`
196+
Union[typing.Sequence[Any],None]0
197+
typing.Sequence[Any]
198+
Any"typing.Sequence
199+
None *b
200+
search_queries_onlyG
201+
Union[builtins.bool,None]
202+
builtins.bool"builtins.bool
203+
None *q
204+
documents`
205+
Union[typing.Sequence[Any],None]0
206+
typing.Sequence[Any]
207+
Any"typing.Sequence
208+
None *>
209+
citation_quality&
210+
Union[Any,None]
211+
Any
212+
None *]
213+
temperatureJ
214+
Union[builtins.float,None]
215+
builtins.float"builtins.float
216+
None *V
217+
218+
max_tokensD
219+
Union[builtins.int,None]
220+
builtins.int" builtins.int
221+
None *\
222+
max_input_tokensD
223+
Union[builtins.int,None]
224+
builtins.int" builtins.int
225+
None *M
226+
kD
227+
Union[builtins.int,None]
228+
builtins.int" builtins.int
229+
None *S
230+
pJ
231+
Union[builtins.float,None]
232+
builtins.float"builtins.float
233+
None *P
234+
seedD
235+
Union[builtins.int,None]
236+
builtins.int" builtins.int
237+
None *�
238+
stop_sequences�
239+
)Union[typing.Sequence[builtins.str],None]N
240+
typing.Sequence[builtins.str]
241+
builtins.str" builtins.str"typing.Sequence
242+
None *c
243+
frequency_penaltyJ
244+
Union[builtins.float,None]
245+
builtins.float"builtins.float
246+
None *b
247+
presence_penaltyJ
248+
Union[builtins.float,None]
249+
builtins.float"builtins.float
250+
None *\
251+
raw_promptingG
252+
Union[builtins.bool,None]
253+
builtins.bool"builtins.bool
254+
None *m
255+
tools`
256+
Union[typing.Sequence[Any],None]0
257+
typing.Sequence[Any]
258+
Any"typing.Sequence
259+
None *t
260+
tool_results`
261+
Union[typing.Sequence[Any],None]0
262+
typing.Sequence[Any]
263+
Any"typing.Sequence
264+
None *`
265+
force_single_stepG
266+
Union[builtins.bool,None]
267+
builtins.bool"builtins.bool
268+
None *=
269+
response_format&
270+
Union[Any,None]
271+
Any
272+
None *�
273+
safety_mode�
274+
MUnion[Literal[builtins.str],Literal[builtins.str],Literal[builtins.str],None]7
275+
Literal[builtins.str] 
276+
builtins.str" builtins.str7
277+
Literal[builtins.str] 
278+
builtins.str" builtins.str7
279+
Literal[builtins.str] 
280+
builtins.str" builtins.str
281+
None *=
282+
request_options&
283+
Union[Any,None]
284+
Any
285+
None *�
286+
__annotations__cohere.client.__annotations__W
287+
builtins.dict[builtins.str,Any]
288+
builtins.str" builtins.str
289+
Any"builtins.dict*%
290+
httpxcohere.client.httpx
291+
Any

0 commit comments

Comments
 (0)