alita-sdk 0.3.348rc1__py3-none-any.whl → 0.3.348rc3__py3-none-any.whl

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.

Potentially problematic release.


This version of alita-sdk might be problematic. Click here for more details.

@@ -345,7 +345,8 @@ class FigmaApiWrapper(NonCodeIndexerToolkit):
345
345
  text_nodes[node['id']] = self.get_texts_recursive(node)
346
346
  # process image nodes
347
347
  if image_nodes:
348
- images = self._client.get_file_images(file_key, image_nodes).images or {}
348
+ file_images = self._client.get_file_images(file_key, image_nodes)
349
+ images = self._client.get_file_images(file_key, image_nodes).images or {} if file_images else {}
349
350
  total_images = len(images)
350
351
  if total_images == 0:
351
352
  logging.info(f"No images found for file {file_key}.")
@@ -17,8 +17,10 @@ def get_tools(tool):
17
17
  toolkit = QtestToolkit.get_toolkit(
18
18
  selected_tools=tool['settings'].get('selected_tools', []),
19
19
  qtest_project_id=tool['settings'].get('qtest_project_id', tool['settings'].get('project_id', None)),
20
+ no_of_tests_shown_in_dql_search=tool['settings'].get('no_of_tests_shown_in_dql_search'),
20
21
  qtest_configuration=tool['settings']['qtest_configuration'],
21
- toolkit_name=tool.get('toolkit_name')
22
+ toolkit_name=tool.get('toolkit_name'),
23
+ llm=tool['settings'].get('llm', None)
22
24
  )
23
25
  return toolkit.tools
24
26
 
@@ -37,7 +39,10 @@ class QtestToolkit(BaseToolkit):
37
39
  'configuration_types': ['qtest']})),
38
40
  qtest_project_id=(int, Field(default=None, description="QTest project id", json_schema_extra={'toolkit_name': True,
39
41
  'max_toolkit_length': QtestToolkit.toolkit_max_length})),
40
- selected_tools=(List[Literal[tuple(selected_tools)]],
42
+ no_of_tests_shown_in_dql_search=(Optional[int], Field(description="Max number of items returned by dql search",
43
+ default=10)),
44
+
45
+ selected_tools=(List[Literal[tuple(selected_tools)]],
41
46
  Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
42
47
  __config__=ConfigDict(json_schema_extra={'metadata': {"label": "QTest", "icon_url": "qtest.svg",
43
48
  "categories": ["test management"],
@@ -1,16 +1,19 @@
1
+ import base64
1
2
  import json
2
3
  import logging
4
+ import re
3
5
  from traceback import format_exc
4
- from typing import Any
6
+ from typing import Any, Optional
5
7
 
6
8
  import swagger_client
7
9
  from langchain_core.tools import ToolException
8
10
  from pydantic import Field, PrivateAttr, model_validator, create_model, SecretStr
9
11
  from sklearn.feature_extraction.text import strip_tags
10
- from swagger_client import TestCaseApi, SearchApi, PropertyResource
12
+ from swagger_client import TestCaseApi, SearchApi, PropertyResource, ModuleApi
11
13
  from swagger_client.rest import ApiException
12
14
 
13
15
  from ..elitea_base import BaseToolApiWrapper
16
+ from ..utils.content_parser import parse_file_content
14
17
 
15
18
  QTEST_ID = "QTest Id"
16
19
 
@@ -64,7 +67,10 @@ logger = logging.getLogger(__name__)
64
67
 
65
68
  QtestDataQuerySearch = create_model(
66
69
  "QtestDataQuerySearch",
67
- dql=(str, Field(description="Qtest Data Query Language (DQL) query string")))
70
+ dql=(str, Field(description="Qtest Data Query Language (DQL) query string")),
71
+ extract_images=(Optional[bool], Field(description="Should images be processed by llm", default=False)),
72
+ prompt=(Optional[str], Field(description="Prompt for image processing", default=None))
73
+ )
68
74
 
69
75
  QtestCreateTestCase = create_model(
70
76
  "QtestCreateTestCase",
@@ -92,6 +98,8 @@ UpdateTestCase = create_model(
92
98
  FindTestCaseById = create_model(
93
99
  "FindTestCaseById",
94
100
  test_id=(str, Field(description="Test case ID e.g. TC-1234")),
101
+ extract_images=(Optional[bool], Field(description="Should images be processed by llm", default=False)),
102
+ prompt=(Optional[str], Field(description="Prompt for image processing", default=None))
95
103
  )
96
104
 
97
105
  DeleteTestCase = create_model(
@@ -99,6 +107,17 @@ DeleteTestCase = create_model(
99
107
  qtest_id=(int, Field(description="Qtest id e.g. 3253490123")),
100
108
  )
101
109
 
110
+ GetModules = create_model(
111
+ "GetModules",
112
+ parent_id=(Optional[int],
113
+ Field(description="ID of the parent Module. Leave it blank to retrieve Modules under root",
114
+ default=None)),
115
+ search=(Optional[str],
116
+ Field(description="The free-text to search for Modules by names. You can utilize this parameter to search for Modules. Leave it blank to retrieve all Modules under root or the parent Module",
117
+ default=None)),
118
+
119
+ )
120
+
102
121
  class QtestApiWrapper(BaseToolApiWrapper):
103
122
  base_url: str
104
123
  qtest_project_id: int
@@ -107,6 +126,7 @@ class QtestApiWrapper(BaseToolApiWrapper):
107
126
  page: int = 1
108
127
  no_of_tests_shown_in_dql_search: int = 10
109
128
  _client: Any = PrivateAttr()
129
+ llm: Any
110
130
 
111
131
  @model_validator(mode='before')
112
132
  @classmethod
@@ -140,6 +160,9 @@ class QtestApiWrapper(BaseToolApiWrapper):
140
160
  # Instantiate the TestCaseApi instance according to the qtest api documentation and swagger client
141
161
  return swagger_client.TestCaseApi(self._client)
142
162
 
163
+ def __instantiate_module_api_instance(self) -> ModuleApi:
164
+ return swagger_client.ModuleApi(self._client)
165
+
143
166
  def __build_body_for_create_test_case(self, test_cases_data: list[dict],
144
167
  folder_to_place_test_cases_to: str = '') -> list:
145
168
  initial_project_properties = self.__get_properties_form_project()
@@ -220,7 +243,7 @@ class QtestApiWrapper(BaseToolApiWrapper):
220
243
  raise ToolException(
221
244
  f"Unable to create test case in project - {self.qtest_project_id} with the following content:\n{test_case_content}.\n\n Stacktrace was {stacktrace}") from e
222
245
 
223
- def __parse_data(self, response_to_parse: dict, parsed_data: list):
246
+ def __parse_data(self, response_to_parse: dict, parsed_data: list, extract_images: bool=False, prompt: str=None):
224
247
  import html
225
248
  for item in response_to_parse['items']:
226
249
  parsed_data_row = {
@@ -231,8 +254,8 @@ class QtestApiWrapper(BaseToolApiWrapper):
231
254
  QTEST_ID: item['id'],
232
255
  'Steps': list(map(lambda step: {
233
256
  'Test Step Number': step[0] + 1,
234
- 'Test Step Description': step[1]['description'],
235
- 'Test Step Expected Result': step[1]['expected']
257
+ 'Test Step Description': self._process_image(step[1]['description'], extract_images, prompt),
258
+ 'Test Step Expected Result': self._process_image(step[1]['expected'], extract_images, prompt)
236
259
  }, enumerate(item['test_steps']))),
237
260
  'Status': ''.join([properties['field_value_name'] for properties in item['properties']
238
261
  if properties['field_name'] == 'Status']),
@@ -245,7 +268,27 @@ class QtestApiWrapper(BaseToolApiWrapper):
245
268
  }
246
269
  parsed_data.append(parsed_data_row)
247
270
 
248
- def __perform_search_by_dql(self, dql: str) -> list:
271
+ def _process_image(self, content: str, extract: bool=False, prompt: str=None):
272
+ #extract image by regex
273
+ img_regex = r'<img\s+src="data:image\/[^;]+;base64,([^"]+)"\s+[^>]*data-filename="([^"]+)"[^>]*>'
274
+
275
+ def replace_image(match):
276
+ base64_content = match.group(1)
277
+ file_name = match.group(2)
278
+
279
+ file_content = base64.b64decode(base64_content)
280
+
281
+ if extract:
282
+ description = f"<img description=\"{parse_file_content(file_content=file_content, file_name=file_name, prompt=prompt, llm=self.llm)}\">"
283
+ else:
284
+ description = ""
285
+
286
+ return description
287
+ #replace image tag by description
288
+ content = re.sub(img_regex, replace_image, content)
289
+ return content
290
+
291
+ def __perform_search_by_dql(self, dql: str, extract_images:bool=False, prompt: str=None) -> list:
249
292
  search_instance: SearchApi = swagger_client.SearchApi(self._client)
250
293
  body = swagger_client.ArtifactSearchParams(object_type='test-cases', fields=['*'],
251
294
  query=dql)
@@ -256,7 +299,7 @@ class QtestApiWrapper(BaseToolApiWrapper):
256
299
  api_response = search_instance.search_artifact(self.qtest_project_id, body, append_test_steps=append_test_steps,
257
300
  include_external_properties=include_external_properties,
258
301
  page_size=self.no_of_items_per_page, page=self.page)
259
- self.__parse_data(api_response, parsed_data)
302
+ self.__parse_data(api_response, parsed_data, extract_images, prompt)
260
303
 
261
304
  if api_response['links']:
262
305
  while api_response['links'][0]['rel'] == 'next':
@@ -265,7 +308,7 @@ class QtestApiWrapper(BaseToolApiWrapper):
265
308
  append_test_steps=append_test_steps,
266
309
  include_external_properties=include_external_properties,
267
310
  page_size=self.no_of_items_per_page, page=next_page)
268
- self.__parse_data(api_response, parsed_data)
311
+ self.__parse_data(api_response, parsed_data, extract_images, prompt)
269
312
  except ApiException as e:
270
313
  stacktrace = format_exc()
271
314
  logger.error(f"Exception when calling SearchApi->search_artifact: \n {stacktrace}")
@@ -333,9 +376,9 @@ class QtestApiWrapper(BaseToolApiWrapper):
333
376
  logger.error(f"Error: {format_exc()}")
334
377
  raise e
335
378
 
336
- def search_by_dql(self, dql: str):
379
+ def search_by_dql(self, dql: str, extract_images:bool=False, prompt: str=None):
337
380
  """Search for the test cases in qTest using Data Query Language """
338
- parsed_data = self.__perform_search_by_dql(dql)
381
+ parsed_data = self.__perform_search_by_dql(dql, extract_images, prompt)
339
382
  return "Found " + str(
340
383
  len(parsed_data)) + f" Qtest test cases:\n" + str(parsed_data[:self.no_of_tests_shown_in_dql_search])
341
384
 
@@ -384,10 +427,10 @@ class QtestApiWrapper(BaseToolApiWrapper):
384
427
  raise ToolException(
385
428
  f"""Unable to update test case in project with id - {self.qtest_project_id} and test id - {test_id}.\n Exception: \n {stacktrace}""") from e
386
429
 
387
- def find_test_case_by_id(self, test_id: str) -> str:
430
+ def find_test_case_by_id(self, test_id: str, extract_images=False, prompt=None) -> str:
388
431
  """ Find the test case by its id. Id should be in format TC-123. """
389
432
  dql: str = f"Id = '{test_id}'"
390
- return f"{self.search_by_dql(dql=dql)}"
433
+ return f"{self.search_by_dql(dql=dql, extract_images=extract_images, prompt=prompt)}"
391
434
 
392
435
  def delete_test_case(self, qtest_id: int) -> str:
393
436
  """ Delete the test case by its id. Id should be in format 3534653120. """
@@ -401,6 +444,20 @@ class QtestApiWrapper(BaseToolApiWrapper):
401
444
  raise ToolException(
402
445
  f"""Unable to delete test case in project with id - {self.qtest_project_id} and qtest_id - {qtest_id}. \n Exception: \n {stacktrace}""") from e
403
446
 
447
+ def get_modules(self, parent_id: int = None, search: str = None):
448
+ """
449
+ :param int project_id: ID of the project (required)
450
+ :param int parent_id: ID of the parent Module. Leave it blank to retrieve Modules under root
451
+ :param str search: The free-text to search for Modules by names. You can utilize this parameter to search for Modules. Leave it blank to retrieve all Modules under root or the parent Module
452
+ """
453
+ module_api = self.__instantiate_module_api_instance()
454
+ kwargs = {}
455
+ if parent_id:
456
+ kwargs["parent_id"] = parent_id
457
+ if search:
458
+ kwargs["search"] = search
459
+ return module_api.get_sub_modules_of(project_id=self.qtest_project_id, **kwargs)
460
+
404
461
  def get_available_tools(self):
405
462
  return [
406
463
  {
@@ -444,5 +501,12 @@ class QtestApiWrapper(BaseToolApiWrapper):
444
501
  "description": """Link tests to Jira requirements. The input is jira issue id and th list of test ids in format '["TC-123", "TC-234", "TC-345"]'""",
445
502
  "args_schema": QtestLinkTestCaseToJiraRequirement,
446
503
  "ref": self.link_tests_to_jira_requirement,
504
+ },
505
+ {
506
+ "name": "get_modules",
507
+ "mode": "get_modules",
508
+ "description": self.get_modules.__doc__,
509
+ "args_schema": GetModules,
510
+ "ref": self.get_modules,
447
511
  }
448
512
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alita_sdk
3
- Version: 0.3.348rc1
3
+ Version: 0.3.348rc3
4
4
  Summary: SDK for building langchain agents using resources from Alita
5
5
  Author-email: Artem Rozumenko <artyom.rozumenko@gmail.com>, Mikalai Biazruchka <mikalai_biazruchka@epam.com>, Roman Mitusov <roman_mitusov@epam.com>, Ivan Krakhmaliuk <lifedj27@gmail.com>, Artem Dubrovskiy <ad13box@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -236,7 +236,7 @@ alita_sdk/tools/custom_open_api/api_wrapper.py,sha256=sDSFpvEqpSvXHGiBISdQQcUecf
236
236
  alita_sdk/tools/elastic/__init__.py,sha256=iwnSRppRpzvJ1da2K3Glu8Uu41MhBDCYbguboLkEbW0,2818
237
237
  alita_sdk/tools/elastic/api_wrapper.py,sha256=pl8CqQxteJAGwyOhMcld-ZgtOTFwwbv42OITQVe8rM0,1948
238
238
  alita_sdk/tools/figma/__init__.py,sha256=W6vIMMkZI2Lmpg6_CRRV3oadaIbVI-qTLmKUh6enqWs,4509
239
- alita_sdk/tools/figma/api_wrapper.py,sha256=yK45guP6oMStTpfNLXRYgIZtNWkuWzgjFm_Vzu-ivNg,33687
239
+ alita_sdk/tools/figma/api_wrapper.py,sha256=k5V2ufv9k3LL5dwjSVi2qIZdx6H0613mlXId3gQudMw,33788
240
240
  alita_sdk/tools/github/__init__.py,sha256=2rHu0zZyZGnLC5CkHgDIhe14N9yCyaEfrrt7ydH8478,5191
241
241
  alita_sdk/tools/github/api_wrapper.py,sha256=uDwYckdnpYRJtb0uZnDkaz2udvdDLVxuCh1tSwspsiU,8411
242
242
  alita_sdk/tools/github/github_client.py,sha256=0YkpD6Zm4X46jMNN57ZIypo2YObtgxCGQokJAF-laFs,86597
@@ -299,8 +299,8 @@ alita_sdk/tools/postman/api_wrapper.py,sha256=bKgnEQVGv3QhqTevzBOwiXxAd0-Y5vUI1-
299
299
  alita_sdk/tools/postman/postman_analysis.py,sha256=2d-Oi2UORosIePIUyncSONw9hY7dw8Zc7BQvCd4aqpg,45115
300
300
  alita_sdk/tools/pptx/__init__.py,sha256=vVUrWnj7KWJgEk9oxGSsCAQ2SMSXrp_SFOdUHYQKcAo,3444
301
301
  alita_sdk/tools/pptx/pptx_wrapper.py,sha256=yyCYcTlIY976kJ4VfPo4dyxj4yeii9j9TWP6W8ZIpN8,29195
302
- alita_sdk/tools/qtest/__init__.py,sha256=bnD6rDM9dS0vpgaUmza4z67WLcZVhJk7S9ZG8OPij0Q,4116
303
- alita_sdk/tools/qtest/api_wrapper.py,sha256=cWXpmjjel9CYIXXjetJkARLYZXqvHufSghctTHN0ggc,22296
302
+ alita_sdk/tools/qtest/__init__.py,sha256=Jf0xo5S_4clXR2TfCbJbB1sFgCbcFQRM-YYX2ltWBzo,4461
303
+ alita_sdk/tools/qtest/api_wrapper.py,sha256=jQSnmYUXyqZyRImzOaxJ7TjrvPwxUw-AWJk3UErwHcw,25597
304
304
  alita_sdk/tools/qtest/tool.py,sha256=kKzNPS4fUC76WQQttQ6kdVANViHEvKE8Kf174MQiNYU,562
305
305
  alita_sdk/tools/rally/__init__.py,sha256=2BPPXJxAOKgfmaxVFVvxndfK0JxOXDLkoRmzu2dUwOE,3512
306
306
  alita_sdk/tools/rally/api_wrapper.py,sha256=mouzU6g0KML4UNapdk0k6Q0pU3MpJuWnNo71n9PSEHM,11752
@@ -350,8 +350,8 @@ alita_sdk/tools/zephyr_scale/api_wrapper.py,sha256=kT0TbmMvuKhDUZc0i7KO18O38JM9S
350
350
  alita_sdk/tools/zephyr_squad/__init__.py,sha256=0ne8XLJEQSLOWfzd2HdnqOYmQlUliKHbBED5kW_Vias,2895
351
351
  alita_sdk/tools/zephyr_squad/api_wrapper.py,sha256=kmw_xol8YIYFplBLWTqP_VKPRhL_1ItDD0_vXTe_UuI,14906
352
352
  alita_sdk/tools/zephyr_squad/zephyr_squad_cloud_client.py,sha256=R371waHsms4sllHCbijKYs90C-9Yu0sSR3N4SUfQOgU,5066
353
- alita_sdk-0.3.348rc1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
354
- alita_sdk-0.3.348rc1.dist-info/METADATA,sha256=EoQDDMvqLF-l2fQt_maEM9xNEg8YSyOTM0zW6fXDT6s,19074
355
- alita_sdk-0.3.348rc1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
356
- alita_sdk-0.3.348rc1.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
357
- alita_sdk-0.3.348rc1.dist-info/RECORD,,
353
+ alita_sdk-0.3.348rc3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
354
+ alita_sdk-0.3.348rc3.dist-info/METADATA,sha256=5aAIwbbXXLrqYverX8ZY63HRvrWbXeK7tPm7BImltU0,19074
355
+ alita_sdk-0.3.348rc3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
356
+ alita_sdk-0.3.348rc3.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
357
+ alita_sdk-0.3.348rc3.dist-info/RECORD,,