alita-sdk 0.3.423__py3-none-any.whl → 0.3.425__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.
- alita_sdk/runtime/langchain/langraph_agent.py +1 -1
- alita_sdk/tools/qtest/api_wrapper.py +94 -21
- {alita_sdk-0.3.423.dist-info → alita_sdk-0.3.425.dist-info}/METADATA +1 -1
- {alita_sdk-0.3.423.dist-info → alita_sdk-0.3.425.dist-info}/RECORD +7 -7
- {alita_sdk-0.3.423.dist-info → alita_sdk-0.3.425.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.423.dist-info → alita_sdk-0.3.425.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.423.dist-info → alita_sdk-0.3.425.dist-info}/top_level.txt +0 -0
|
@@ -244,7 +244,7 @@ class PrinterNode(Runnable):
|
|
|
244
244
|
result = {}
|
|
245
245
|
logger.debug(f"Initial text pattern: {self.input_mapping}")
|
|
246
246
|
mapping = propagate_the_input_mapping(self.input_mapping, [], state)
|
|
247
|
-
if
|
|
247
|
+
if mapping.get(PRINTER) is None:
|
|
248
248
|
raise ToolException(f"PrinterNode requires '{PRINTER}' field in input mapping")
|
|
249
249
|
formatted_output = mapping[PRINTER]
|
|
250
250
|
logger.debug(f"Formatted output: {formatted_output}")
|
|
@@ -44,6 +44,10 @@ Test Type: Category of test (e.g., 'Functional', 'Regression', 'Smoke').
|
|
|
44
44
|
Precondition: Prerequisites for the test, formatted as: <Step1> <Step2> Leave blank if none.
|
|
45
45
|
Steps: Array of test steps with Description and Expected Result.
|
|
46
46
|
|
|
47
|
+
**Multi-select fields**: For fields that allow multiple values (e.g., Team, Assigned To etc.), you can provide:
|
|
48
|
+
- Single value: "Team": "Epam"
|
|
49
|
+
- Multiple values: "Team": ["Epam", "EJ"]
|
|
50
|
+
|
|
47
51
|
**For Updates**: Include only the fields you want to modify. The system will validate property values against project configuration.
|
|
48
52
|
|
|
49
53
|
### EXAMPLE
|
|
@@ -57,6 +61,7 @@ Steps: Array of test steps with Description and Expected Result.
|
|
|
57
61
|
"Priority": "",
|
|
58
62
|
"Test Type": "Functional",
|
|
59
63
|
"Precondition": "<ONLY provided by user precondition>",
|
|
64
|
+
"Team": ["Epam", "EJ"],
|
|
60
65
|
"Steps": [
|
|
61
66
|
{{ "Test Step Number": 1, "Test Step Description": "Navigate to url", "Test Step Expected Result": "Page content is loaded"}},
|
|
62
67
|
{{ "Test Step Number": 2, "Test Step Description": "Click 'Login'", "Test Step Expected Result": "Form is expanded"}},
|
|
@@ -257,19 +262,57 @@ class QtestApiWrapper(BaseToolApiWrapper):
|
|
|
257
262
|
|
|
258
263
|
field_def = field_definitions[field_name]
|
|
259
264
|
field_id = field_def['field_id']
|
|
265
|
+
data_type = field_def.get('data_type')
|
|
266
|
+
is_multiple = field_def.get('multiple', False)
|
|
267
|
+
|
|
268
|
+
# Normalize field_value to list for consistent processing
|
|
269
|
+
# Multi-select fields can receive: "value", ["value1", "value2"], or ["value1"]
|
|
270
|
+
# Single-select fields: "value" only
|
|
271
|
+
if is_multiple:
|
|
272
|
+
# Convert to list if not already
|
|
273
|
+
values_to_process = field_value if isinstance(field_value, list) else [field_value]
|
|
274
|
+
else:
|
|
275
|
+
# Single-select: keep as single value
|
|
276
|
+
values_to_process = [field_value]
|
|
260
277
|
|
|
261
|
-
# Validate value for dropdown fields (only if field has allowed values)
|
|
278
|
+
# Validate value(s) for dropdown fields (only if field has allowed values)
|
|
262
279
|
if field_def['values']:
|
|
263
|
-
# Field has allowed values (dropdown/combobox) - validate strictly
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
280
|
+
# Field has allowed values (dropdown/combobox/user fields) - validate strictly
|
|
281
|
+
value_ids = []
|
|
282
|
+
value_names = []
|
|
283
|
+
|
|
284
|
+
for single_value in values_to_process:
|
|
285
|
+
if single_value not in field_def['values']:
|
|
286
|
+
available = ", ".join(sorted(field_def['values'].keys()))
|
|
287
|
+
validation_errors.append(
|
|
288
|
+
f"❌ Invalid value '{single_value}' for field '{field_name}'. "
|
|
289
|
+
f"Allowed values: {available}"
|
|
290
|
+
)
|
|
291
|
+
continue # Skip this value, but continue validating others
|
|
292
|
+
|
|
293
|
+
# Valid value - add to lists
|
|
294
|
+
value_ids.append(field_def['values'][single_value])
|
|
295
|
+
value_names.append(single_value)
|
|
296
|
+
|
|
297
|
+
# If all values were invalid, skip this field
|
|
298
|
+
if not value_ids:
|
|
299
|
+
continue
|
|
300
|
+
|
|
301
|
+
# Format based on field type and value count
|
|
302
|
+
if is_multiple and len(value_ids) == 1:
|
|
303
|
+
# Single value in multi-select field: bracketed string "[419950]"
|
|
304
|
+
# This includes single user assignment: "[626983]"
|
|
305
|
+
field_value_id = f"[{value_ids[0]}]"
|
|
306
|
+
field_value_name = f"[{value_names[0]}]" if data_type == 5 else value_names[0]
|
|
307
|
+
elif is_multiple:
|
|
308
|
+
# Multiple values in multi-select: bracketed string with comma-separated IDs
|
|
309
|
+
ids_str = ",".join(str(vid) for vid in value_ids)
|
|
310
|
+
field_value_id = f"[{ids_str}]"
|
|
311
|
+
field_value_name = ", ".join(value_names)
|
|
312
|
+
else:
|
|
313
|
+
# Regular single-select dropdown: plain ID
|
|
314
|
+
field_value_id = value_ids[0]
|
|
315
|
+
field_value_name = value_names[0]
|
|
273
316
|
else:
|
|
274
317
|
# Text field or field without restricted values - use value directly
|
|
275
318
|
# No validation needed - users can write anything (by design)
|
|
@@ -400,14 +443,22 @@ class QtestApiWrapper(BaseToolApiWrapper):
|
|
|
400
443
|
field_mapping[field_name] = {
|
|
401
444
|
'field_id': field.id,
|
|
402
445
|
'required': getattr(field, 'required', False),
|
|
446
|
+
'data_type': getattr(field, 'data_type', None), # 5 = user field
|
|
447
|
+
'multiple': getattr(field, 'multiple', False), # True = multi-select, needs array format
|
|
403
448
|
'values': {}
|
|
404
449
|
}
|
|
405
450
|
|
|
406
|
-
# Map allowed values if field has them (dropdown/combobox fields)
|
|
451
|
+
# Map allowed values if field has them (dropdown/combobox/user fields)
|
|
452
|
+
# Only include active values (is_active=True)
|
|
407
453
|
if hasattr(field, 'allowed_values') and field.allowed_values:
|
|
408
454
|
for allowed_value in field.allowed_values:
|
|
455
|
+
# Skip inactive values (deleted/deprecated options)
|
|
456
|
+
if hasattr(allowed_value, 'is_active') and not allowed_value.is_active:
|
|
457
|
+
continue
|
|
458
|
+
|
|
409
459
|
# AllowedValueResource has 'label' for the display name and 'value' for the ID
|
|
410
460
|
# Note: 'value' is the field_value, not 'id'
|
|
461
|
+
# For user fields (data_type=5), label is user name and value is user ID
|
|
411
462
|
value_label = allowed_value.label
|
|
412
463
|
value_id = allowed_value.value
|
|
413
464
|
field_mapping[field_name]['values'][value_label] = value_id
|
|
@@ -496,27 +547,49 @@ class QtestApiWrapper(BaseToolApiWrapper):
|
|
|
496
547
|
|
|
497
548
|
def __parse_data(self, response_to_parse: dict, parsed_data: list, extract_images: bool=False, prompt: str=None):
|
|
498
549
|
import html
|
|
550
|
+
|
|
551
|
+
# Get field definitions to ensure all fields are included (uses cached version)
|
|
552
|
+
field_definitions = self.__get_field_definitions_cached()
|
|
553
|
+
|
|
499
554
|
for item in response_to_parse['items']:
|
|
555
|
+
# Start with core fields (always present)
|
|
500
556
|
parsed_data_row = {
|
|
501
557
|
'Id': item['pid'],
|
|
558
|
+
'Name': item['name'],
|
|
502
559
|
'Description': html.unescape(strip_tags(item['description'])),
|
|
503
560
|
'Precondition': html.unescape(strip_tags(item['precondition'])),
|
|
504
|
-
'Name': item['name'],
|
|
505
561
|
QTEST_ID: item['id'],
|
|
506
562
|
'Steps': list(map(lambda step: {
|
|
507
563
|
'Test Step Number': step[0] + 1,
|
|
508
564
|
'Test Step Description': self._process_image(step[1]['description'], extract_images, prompt),
|
|
509
565
|
'Test Step Expected Result': self._process_image(step[1]['expected'], extract_images, prompt)
|
|
510
566
|
}, enumerate(item['test_steps']))),
|
|
511
|
-
'Status': ''.join([properties['field_value_name'] for properties in item['properties']
|
|
512
|
-
if properties['field_name'] == 'Status']),
|
|
513
|
-
'Automation': ''.join([properties['field_value_name'] for properties in item['properties']
|
|
514
|
-
if properties['field_name'] == 'Automation']),
|
|
515
|
-
'Type': ''.join([properties['field_value_name'] for properties in item['properties']
|
|
516
|
-
if properties['field_name'] == 'Type']),
|
|
517
|
-
'Priority': ''.join([properties['field_value_name'] for properties in item['properties']
|
|
518
|
-
if properties['field_name'] == 'Priority']),
|
|
519
567
|
}
|
|
568
|
+
|
|
569
|
+
# Dynamically add all custom fields from project configuration
|
|
570
|
+
# This ensures consistency and includes fields even if they have null/empty values
|
|
571
|
+
for field_name in field_definitions.keys():
|
|
572
|
+
field_def = field_definitions[field_name]
|
|
573
|
+
is_multiple = field_def.get('multiple', False)
|
|
574
|
+
|
|
575
|
+
# Find the property value in the response (if exists)
|
|
576
|
+
field_value = None
|
|
577
|
+
for prop in item['properties']:
|
|
578
|
+
if prop['field_name'] == field_name:
|
|
579
|
+
# Use field_value_name if available (for dropdowns), otherwise field_value
|
|
580
|
+
field_value = prop.get('field_value_name') or prop.get('field_value') or ''
|
|
581
|
+
break
|
|
582
|
+
|
|
583
|
+
# Format based on field type
|
|
584
|
+
if is_multiple and (field_value is None or field_value == ''):
|
|
585
|
+
# Multi-select field with no value: show empty array with hint
|
|
586
|
+
parsed_data_row[field_name] = '[] (multi-select)'
|
|
587
|
+
elif field_value is not None:
|
|
588
|
+
parsed_data_row[field_name] = field_value
|
|
589
|
+
else:
|
|
590
|
+
# Regular field with no value
|
|
591
|
+
parsed_data_row[field_name] = ''
|
|
592
|
+
|
|
520
593
|
parsed_data.append(parsed_data_row)
|
|
521
594
|
|
|
522
595
|
def _process_image(self, content: str, extract: bool=False, prompt: str=None):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: alita_sdk
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.425
|
|
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
|
|
@@ -45,7 +45,7 @@ alita_sdk/runtime/langchain/assistant.py,sha256=qKoEjbGuUnX-OZDHmSaK3plb1jON9unz
|
|
|
45
45
|
alita_sdk/runtime/langchain/chat_message_template.py,sha256=kPz8W2BG6IMyITFDA5oeb5BxVRkHEVZhuiGl4MBZKdc,2176
|
|
46
46
|
alita_sdk/runtime/langchain/constants.py,sha256=I3dwexVp_Qq3MueRA2ClLgFDEhk4BkJhgR6m7V0gVPc,3404
|
|
47
47
|
alita_sdk/runtime/langchain/indexer.py,sha256=0ENHy5EOhThnAiYFc7QAsaTNp9rr8hDV_hTK8ahbatk,37592
|
|
48
|
-
alita_sdk/runtime/langchain/langraph_agent.py,sha256=
|
|
48
|
+
alita_sdk/runtime/langchain/langraph_agent.py,sha256=sAdDojp7lOC2jyaBPS3MP8hV_EhjsZuyOqUT3abf2Wk,51647
|
|
49
49
|
alita_sdk/runtime/langchain/mixedAgentParser.py,sha256=M256lvtsL3YtYflBCEp-rWKrKtcY1dJIyRGVv7KW9ME,2611
|
|
50
50
|
alita_sdk/runtime/langchain/mixedAgentRenderes.py,sha256=asBtKqm88QhZRILditjYICwFVKF5KfO38hu2O-WrSWE,5964
|
|
51
51
|
alita_sdk/runtime/langchain/store_manager.py,sha256=i8Fl11IXJhrBXq1F1ukEVln57B1IBe-tqSUvfUmBV4A,2218
|
|
@@ -303,7 +303,7 @@ alita_sdk/tools/postman/postman_analysis.py,sha256=ckc2BfKEop0xnmLPksVRE_Y94ixuq
|
|
|
303
303
|
alita_sdk/tools/pptx/__init__.py,sha256=vVUrWnj7KWJgEk9oxGSsCAQ2SMSXrp_SFOdUHYQKcAo,3444
|
|
304
304
|
alita_sdk/tools/pptx/pptx_wrapper.py,sha256=yyCYcTlIY976kJ4VfPo4dyxj4yeii9j9TWP6W8ZIpN8,29195
|
|
305
305
|
alita_sdk/tools/qtest/__init__.py,sha256=Jf0xo5S_4clXR2TfCbJbB1sFgCbcFQRM-YYX2ltWBzo,4461
|
|
306
|
-
alita_sdk/tools/qtest/api_wrapper.py,sha256=
|
|
306
|
+
alita_sdk/tools/qtest/api_wrapper.py,sha256=kxH4H1mFm4-_xqJ3js92YzT9sJ-6XC30moC1WCExano,40926
|
|
307
307
|
alita_sdk/tools/qtest/tool.py,sha256=kKzNPS4fUC76WQQttQ6kdVANViHEvKE8Kf174MQiNYU,562
|
|
308
308
|
alita_sdk/tools/rally/__init__.py,sha256=2BPPXJxAOKgfmaxVFVvxndfK0JxOXDLkoRmzu2dUwOE,3512
|
|
309
309
|
alita_sdk/tools/rally/api_wrapper.py,sha256=mouzU6g0KML4UNapdk0k6Q0pU3MpJuWnNo71n9PSEHM,11752
|
|
@@ -353,8 +353,8 @@ alita_sdk/tools/zephyr_scale/api_wrapper.py,sha256=kT0TbmMvuKhDUZc0i7KO18O38JM9S
|
|
|
353
353
|
alita_sdk/tools/zephyr_squad/__init__.py,sha256=0ne8XLJEQSLOWfzd2HdnqOYmQlUliKHbBED5kW_Vias,2895
|
|
354
354
|
alita_sdk/tools/zephyr_squad/api_wrapper.py,sha256=kmw_xol8YIYFplBLWTqP_VKPRhL_1ItDD0_vXTe_UuI,14906
|
|
355
355
|
alita_sdk/tools/zephyr_squad/zephyr_squad_cloud_client.py,sha256=R371waHsms4sllHCbijKYs90C-9Yu0sSR3N4SUfQOgU,5066
|
|
356
|
-
alita_sdk-0.3.
|
|
357
|
-
alita_sdk-0.3.
|
|
358
|
-
alita_sdk-0.3.
|
|
359
|
-
alita_sdk-0.3.
|
|
360
|
-
alita_sdk-0.3.
|
|
356
|
+
alita_sdk-0.3.425.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
357
|
+
alita_sdk-0.3.425.dist-info/METADATA,sha256=3mtvWLA2jfZaDNc8TDWe8zHdBmWvnqTpN5PIdzDjjYA,19071
|
|
358
|
+
alita_sdk-0.3.425.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
359
|
+
alita_sdk-0.3.425.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
|
|
360
|
+
alita_sdk-0.3.425.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|