How to use warn_or_raise method in lisa

Best Python code snippet using lisa_python

header.py

Source:header.py Github

copy

Full Screen

...49 # first get initial size50 argtypes, attr_names, attr_text, num_attributes = func_config()51 func.argtypes = argtypes52 retcode = func(self.fh, attr_names, attr_text, num_attributes)53 warn_or_raise(retcode, func)54 # get actual array size and clean55 array_size = num_attributes.value56 self.spssio.spssFreeAttributes(attr_names, attr_text, num_attributes)57 if array_size == 0:58 return {}59 else:60 # get attributes61 argtypes, attr_names, attr_text, num_attributes = func_config(array_size)62 func.argtypes = argtypes63 retcode = func(self.fh, attr_names, attr_text, num_attributes)64 warn_or_raise(retcode, func)65 # clean66 self.spssio.spssFreeAttributes(attr_names, attr_text, num_attributes)67 attr_names = (x.decode(self.encoding) for x in attr_names[0])68 attr_text = (x.decode(self.encoding) for x in attr_text[0])69 return dict(zip(attr_names, attr_text))70 @file_attributes.setter71 def file_attributes(self, attributes: dict) -> None:72 array_size = len(attributes)73 attr_names = []74 attr_text = []75 for name, text in attributes.items():76 attr_names.append(str(name).encode(self.encoding))77 attr_text.append(str(text).encode(self.encoding))78 attr_names = (c_char_p * array_size)(*attr_names)79 attr_text = (c_char_p * array_size)(*attr_text)80 func = self.spssio.spssSetFileAttributes81 func.argtypes = [82 c_int,83 POINTER(c_char_p * array_size),84 POINTER(c_char_p * array_size),85 c_int,86 ]87 retcode = func(self.fh, attr_names, attr_text, array_size)88 warn_or_raise(retcode, func)89 @property90 def var_names(self) -> list:91 """Variable names92 May return a filtered list when returned as part of a metadata object93 if only a subset of variables are specified to be used (e.g., usecols in read_sav).94 """95 num_vars = self.var_count96 func = self.spssio.spssGetVarNames97 func.argtypes = [98 c_int,99 POINTER(c_int),100 POINTER(POINTER(c_char_p * num_vars)),101 POINTER(POINTER(c_int * num_vars)),102 ]103 _num_vars = c_int()104 var_names = POINTER(c_char_p * num_vars)()105 var_types = POINTER(c_int * num_vars)()106 retcode = func(self.fh, _num_vars, var_names, var_types)107 warn_or_raise(retcode, func)108 var_name_list = [var_names[0][i].decode(self.encoding) for i in range(num_vars)]109 self.spssio.spssFreeVarNames(var_names, var_types, _num_vars)110 return var_name_list111 @property112 def var_types(self) -> dict:113 """Variable types114 May return a filtered dictionary when returned as part of a metadata object115 if only a subset of variables are specified to be used (e.g., usecols in read_sav).116 """117 num_vars = self.var_count118 func = self.spssio.spssGetVarNames119 func.argtypes = [120 c_int,121 POINTER(c_int),122 POINTER(POINTER(c_char_p * num_vars)),123 POINTER(POINTER(c_int * num_vars)),124 ]125 _num_vars = c_int()126 var_names = POINTER(c_char_p * num_vars)()127 var_types = POINTER(c_int * num_vars)()128 retcode = func(self.fh, _num_vars, var_names, var_types)129 warn_or_raise(retcode, func)130 var_types_dict = {131 var_names[0][i].decode(self.encoding): var_types[0][i] for i in range(num_vars)132 }133 self.spssio.spssFreeVarNames(var_names, var_types, _num_vars)134 return var_types_dict135 @var_types.setter136 def var_types(self, var_types: dict):137 for var_name, var_type in var_types.items():138 self._add_var(var_name, var_type)139 def _add_var(self, var_name, var_type=0):140 func = self.spssio.spssSetVarName141 func.argtypes = [c_int, c_char_p, c_int]142 retcode = func(self.fh, var_name.encode(self.encoding), c_int(var_type))143 warn_or_raise(retcode, func, var_name, var_type)144 def _get_var_handle(self, var_name):145 func = self.spssio.spssGetVarHandle146 func.argtypes = [c_int, c_char_p, POINTER(c_double)]147 var_handle = c_double()148 retcode = func(self.fh, var_name.encode(self.encoding), var_handle)149 warn_or_raise(retcode, func, var_name)150 return var_handle151 @property152 def var_handles(self) -> dict:153 """Variable handles references154 Used when calling I/O module procedures that use155 variable handles instead of variable names as arguments156 """157 func = self.spssio.spssGetVarHandle158 func.argtypes = [c_int, c_char_p, POINTER(c_double)]159 var_handles = {}160 for var_name in self.var_names:161 var_handle = c_double()162 retcode = func(self.fh, var_name.encode(self.encoding), var_handle)163 warn_or_raise(retcode, func, var_name)164 var_handles[var_name] = var_handle165 return var_handles166 def _get_var_format(self, var_name):167 func = self.spssio.spssGetVarPrintFormat168 func.argtypes = [c_int, c_char_p, POINTER(c_int), POINTER(c_int), POINTER(c_int)]169 f_type = c_int()170 f_dec = c_int()171 f_width = c_int()172 retcode = func(self.fh, var_name.encode(self.encoding), f_type, f_dec, f_width)173 warn_or_raise(retcode, func, var_name)174 return (f_type.value, f_width.value, f_dec.value)175 @property176 def var_formats_tuple(self) -> dict:177 """Variable formats as tuples in the form (type, width, decimals)178 ex. (5, 8, 2) instead of F8.2179 """180 var_formats = {}181 for var_name in self.var_names:182 var_formats[var_name] = self._get_var_format(var_name)183 return var_formats184 @property185 def var_formats(self) -> dict:186 """Variable formats as strings187 Use var_formats_tuple property for formats as tuples188 """189 var_formats = {}190 for var_name in self.var_names:191 f_type, f_width, f_dec = self._get_var_format(var_name)192 var_formats[var_name] = (193 spss_formats_simple[f_type]194 + str(int(f_width))195 + ("." + str(int(f_dec)) if f_dec else "")196 )197 return var_formats198 @var_formats.setter199 def var_formats(self, var_formats: dict):200 var_names = self.var_names201 for var_name, var_format in var_formats.items():202 if var_name in var_names:203 # convert to tuple in case string type is supplied204 var_format = varformat_to_tuple(var_format)205 f_type, f_width, f_dec = var_format206 for func in (self.spssio.spssSetVarPrintFormat, self.spssio.spssSetVarWriteFormat):207 func.argtypes = [c_int, c_char_p, c_int, c_int, c_int]208 retcode = func(209 self.fh,210 var_name.encode(self.encoding),211 c_int(f_type),212 c_int(f_dec),213 c_int(f_width),214 )215 warn_or_raise(retcode, func, var_name, var_format)216 @property217 def var_measure_levels(self) -> dict:218 """Variable measure levels219 Measure levels are returned as strings.220 When setting, input accepts either strings or numerics.221 - 0 = unknown222 - 1 = nominal223 - 2 = ordinal224 - 3 = scale225 """226 func = self.spssio.spssGetVarMeasureLevel227 func.argtypes = [c_int, c_char_p, POINTER(c_int)]228 var_levels = {}229 for var_name in self.var_names:230 level = c_int()231 retcode = func(self.fh, var_name.encode(self.encoding), level)232 warn_or_raise(retcode, func, var_name)233 var_levels[var_name] = measure_levels_str[level.value]234 return var_levels235 @var_measure_levels.setter236 def var_measure_levels(self, var_measure_levels: dict):237 var_names = self.var_names238 func = self.spssio.spssSetVarMeasureLevel239 func.argtypes = [c_int, c_char_p, c_int]240 for var_name, measure_level in var_measure_levels.items():241 measure_level = measure_levels.get(str(measure_level).lower(), measure_level)242 if var_name in var_names:243 retcode = func(self.fh, var_name.encode(self.encoding), c_int(measure_level))244 warn_or_raise(retcode, func, var_name, measure_level)245 @property246 def var_alignments(self) -> dict:247 """Variable alignments248 Alignments are returned as strings.249 When setting, input accepts either strings or numerics.250 - 0 = left251 - 1 = right252 - 2 = center253 """254 func = self.spssio.spssGetVarAlignment255 func.argtypes = [c_int, c_char_p, POINTER(c_int)]256 var_alignments = {}257 for var_name in self.var_names:258 align = c_int()259 retcode = func(self.fh, var_name.encode(self.encoding), align)260 warn_or_raise(retcode, func, var_name)261 var_alignments[var_name] = alignments_str[align.value]262 return var_alignments263 @var_alignments.setter264 def var_alignments(self, var_alignments: dict):265 var_names = self.var_names266 func = self.spssio.spssSetVarAlignment267 func.argtypes = [c_int, c_char_p, c_int]268 for var_name, align in var_alignments.items():269 align = alignments.get(str(align).lower(), align)270 if var_name in var_names:271 retcode = func(self.fh, var_name.encode(self.encoding), align)272 warn_or_raise(retcode, func, var_name, align)273 @property274 def var_column_widths(self) -> dict:275 """Column display widths276 Manually set column widths or specify 0 to use SPSS' algorithm to assign a width277 """278 func = self.spssio.spssGetVarColumnWidth279 func.argtypes = [c_int, c_char_p, POINTER(c_int)]280 widths = {}281 for var_name in self.var_names:282 column_width = c_int()283 retcode = func(self.fh, var_name.encode(self.encoding), column_width)284 warn_or_raise(retcode, func, var_name)285 widths[var_name] = column_width.value286 return widths287 @var_column_widths.setter288 def var_column_widths(self, var_column_widths: dict):289 var_names = self.var_names290 func = self.spssio.spssSetVarColumnWidth291 func.argtypes = [c_int, c_char_p, c_int]292 for var_name, column_width in var_column_widths.items():293 if var_name in var_names:294 retcode = func(self.fh, var_name.encode(self.encoding), column_width)295 warn_or_raise(retcode, func, var_name, column_width)296 @property297 def var_labels(self) -> dict:298 """Variable labels"""299 len_buff = SPSS_MAX_VARLABEL + 1300 buffer = create_string_buffer(len_buff)301 func = self.spssio.spssGetVarLabelLong302 func.argtypes = [c_int, c_char_p, c_char_p, c_int, POINTER(c_int)]303 var_labels = {}304 for var_name in self.var_names:305 len_label = c_int()306 retcode = func(self.fh, var_name.encode(self.encoding), buffer, len_buff, len_label)307 warn_or_raise(retcode, func, var_name)308 var_labels[var_name] = buffer.value.decode(self.encoding)309 return var_labels310 @var_labels.setter311 def var_labels(self, labels: dict):312 var_names = self.var_names313 func = self.spssio.spssSetVarLabel314 func.argtypes = [c_int, c_char_p, c_char_p]315 for var_name, var_label in labels.items():316 if var_name in var_names:317 retcode = func(318 self.fh, var_name.encode(self.encoding), var_label.encode(self.encoding)319 )320 warn_or_raise(retcode, func, var_name, var_label)321 @property322 def var_roles(self) -> dict:323 """Variable roles324 Roles are returned as strings.325 When setting, input accepts either strings or numerics.326 - 0 = input327 - 1 = target328 - 2 = both329 - 3 = none330 - 4 = partition331 - 5 = split332 - 6 = frequency333 - 7 = recordid334 """335 func = self.spssio.spssGetVarRole336 func.argtypes = [c_int, c_char_p, POINTER(c_int)]337 var_roles = {}338 for var_name in self.var_names:339 role = c_int()340 retcode = func(self.fh, var_name.encode(self.encoding), role)341 warn_or_raise(retcode, func, var_name)342 var_roles[var_name] = roles_str[role.value]343 return var_roles344 @var_roles.setter345 def var_roles(self, var_roles: dict):346 var_names = self.var_names347 func = self.spssio.spssSetVarRole348 func.argtypes = [c_int, c_char_p, c_int]349 for var_name, role in var_roles.items():350 role = roles.get(str(role).lower(), role)351 if var_name in var_names:352 retcode = func(self.fh, var_name.encode(self.encoding), role)353 warn_or_raise(retcode, func, var_name, role)354 def _get_var_n_value_labels(self, var_name):355 func = self.spssio.spssGetVarNValueLabels356 def func_config(var_name, size=0):357 argtypes = [358 c_int,359 c_char_p,360 POINTER(POINTER(c_double * size)),361 POINTER(POINTER(c_char_p * size)),362 POINTER(c_int),363 ]364 values_arr = POINTER((c_double * size))()365 labels_arr = POINTER((c_char_p * size))()366 num_labels = c_int()367 return argtypes, var_name, values_arr, labels_arr, num_labels368 # initial function call to get number of labels369 argtypes, var_name, values_arr, labels_arr, num_labels = func_config(var_name)370 func.argtypes = argtypes371 retcode = func(self.fh, var_name.encode(self.encoding), values_arr, labels_arr, num_labels)372 if retcode > 0:373 self.spssio.spssFreeVarNValueLabels(values_arr, labels_arr, num_labels)374 warn_or_raise(retcode, func, var_name)375 elif num_labels.value > 0:376 # if function call was successful and variable has value labels377 argtypes, var_name, values_arr, labels_arr, num_labels = func_config(378 var_name, num_labels.value379 )380 func.argtypes = argtypes381 retcode = func(382 self.fh, var_name.encode(self.encoding), values_arr, labels_arr, num_labels383 )384 warn_or_raise(retcode, func, var_name)385 value_labels = {386 values_arr[0][i]: labels_arr[0][i].decode(self.encoding)387 for i in range(num_labels.value)388 }389 self.spssio.spssFreeVarNValueLabels(values_arr, labels_arr, num_labels)390 return value_labels391 else:392 return {}393 def _get_var_c_value_labels(self, var_name):394 func = self.spssio.spssGetVarCValueLabels395 def func_config(var_name, size=0):396 argtypes = [397 c_int,398 c_char_p,399 POINTER(POINTER(c_char_p * size)),400 POINTER(POINTER(c_char_p * size)),401 POINTER(c_int),402 ]403 values_arr = POINTER((c_char_p * size))()404 labels_arr = POINTER((c_char_p * size))()405 num_labels = c_int()406 return argtypes, var_name, values_arr, labels_arr, num_labels407 # initial function call to get number of labels408 argtypes, var_name, values_arr, labels_arr, num_labels = func_config(var_name)409 func.argtypes = argtypes410 retcode = func(self.fh, var_name.encode(self.encoding), values_arr, labels_arr, num_labels)411 if retcode > 0:412 self.spssio.spssFreeVarCValueLabels(values_arr, labels_arr, num_labels)413 warn_or_raise(retcode, func, var_name)414 elif num_labels.value > 0:415 # if function call was successful and variable has value labels416 argtypes, var_name, values_arr, labels_arr, num_labels = func_config(417 var_name, num_labels.value418 )419 func.argtypes = argtypes420 retcode = func(421 self.fh, var_name.encode(self.encoding), values_arr, labels_arr, num_labels422 )423 warn_or_raise(retcode, func, var_name)424 value_labels = {425 values_arr[0][i]426 .decode(self.encoding)427 .rstrip(): labels_arr[0][i]428 .decode(self.encoding)429 for i in range(num_labels.value)430 }431 self.spssio.spssFreeVarCValueLabels(values_arr, labels_arr, num_labels)432 return value_labels433 else:434 return {}435 @property436 def var_value_labels(self) -> dict:437 """Variable value labels438 Nested dictionary of variables with their value labels (if defined) as sub-dictionaries439 Note: value labels only work for numeric and short string variables (length <= 8)440 """441 var_value_labels = {}442 for var_name, var_type in self.var_types.items():443 if var_type == 0:444 var_value_labels[var_name] = self._get_var_n_value_labels(var_name)445 elif var_type <= 8:446 var_value_labels[var_name] = self._get_var_c_value_labels(var_name)447 return {k: v for k, v in var_value_labels.items() if v}448 def _set_var_n_value_label(self, var_name, value, label):449 func = self.spssio.spssSetVarNValueLabel450 func.argtypes = [c_int, c_char_p, c_double, c_char_p]451 retcode = func(452 self.fh, var_name.encode(self.encoding), c_double(value), label.encode(self.encoding)453 )454 warn_or_raise(retcode, func, var_name, value, label)455 def _set_var_c_value_label(self, var_name, value, label):456 func = self.spssio.spssSetVarCValueLabel457 func.argtypes = [c_int, c_char_p, c_char_p, c_char_p]458 retcode = func(459 self.fh,460 var_name.encode(self.encoding),461 value.encode(self.encoding),462 label.encode(self.encoding),463 )464 warn_or_raise(retcode, func, var_name, value, label)465 @var_value_labels.setter466 def var_value_labels(self, var_value_labels: dict):467 var_types = self.var_types468 for var_name, value_labels in var_value_labels.items():469 var_type = var_types.get(var_name)470 if var_type is not None:471 if var_type:472 func = self._set_var_c_value_label473 else:474 func = self._set_var_n_value_label475 for value, label in value_labels.items():476 func(var_name, value, label)477 @property478 def mrsets_count(self) -> int:479 """Number of multi response set definitions480 Needed if using spssGetMultRespDefByIndex.481 Otherwise, len(mrsets) should be equivalent.482 """483 func = self.spssio.spssGetMultRespCount484 func.argtypes = [c_int, POINTER(c_int)]485 count = c_int()486 retcode = func(self.fh, count)487 warn_or_raise(retcode, func)488 return count.value489 def _parse_mrset_c(self, attr: str) -> dict:490 d = {}491 d["type"] = "C"492 d["is_dichotomy"] = False493 idx = 2494 d["value_length"], d["counted_value"] = None, None495 label_length = attr[idx:].split(" ", 1)[0]496 idx += len(label_length) + 1497 d["label"] = attr[idx:][: int(label_length.strip())]498 idx += len(d["label"]) + 1499 d["variable_list"] = attr[idx:].split()500 return d501 def _parse_mrset_d(self, attr: str) -> dict:502 d = {}503 d["type"] = "D"504 d["is_dichotomy"] = True505 idx = 1506 value_length = attr[idx:].split(" ", 1)[0]507 idx += len(value_length) + 1508 d["counted_value"] = attr[idx:][: int(value_length.strip())]509 idx += len(d["counted_value"]) + 1510 label_length = attr[idx:].split(" ", 1)[0]511 idx += len(label_length) + 1512 d["label"] = attr[idx:][: int(label_length.strip())]513 idx += len(d["label"]) + 1514 d["variable_list"] = attr[idx:].split()515 return d516 def _parse_mrset_e(self, attr: str) -> dict:517 d = {}518 d["type"] = "E"519 d["is_dichotomy"] = True520 d["use_category_labels"] = True521 d["use_first_var_label"] = attr[3] == "1"522 idx = 4 + d["use_first_var_label"]523 value_length = attr[idx:].split(" ", 1)[0]524 idx += len(value_length) + 1525 d["counted_value"] = attr[idx:][: int(value_length.strip())]526 idx += len(d["counted_value"]) + 1527 label_length = attr[idx:].split(" ", 1)[0]528 idx += len(label_length) + 1529 d["label"] = attr[idx:][: int(label_length.strip())]530 idx += len(d["label"]) + 1531 d["variable_list"] = attr[idx:].split()532 return d533 @property534 def mrsets(self) -> dict:535 """Multi response set definitions536 Multi response sets contain the following attributes537 - label : set label538 - is_dichotomy : whether set is dichotomous (True) or Category (False)539 - counted_value : counted value for dichotomous sets540 - use_category_labels : whether to use counted value labels instead of variable labels541 - use_first_var_label : whether to use first var label as set label542 - variable_list : list of variables in the set543 Notes544 -----545 mrset name must begin with a "$".546 variable_list is the only required attribute.547 However, if this is the only included attribute, then is_dichotomy is assumed to be False.548 If is_dichotomy is True, counted_value must be specified.549 If is_dichotomy is None and counted_value is not None, is_dichotomy is assumed to be True.550 Numeric dichotomous sets only accept integers for a counted value.551 use_category_labels is only applicable for dichotomous sets.552 Setting this to True turns the set into an "extended" mrset definition.553 use_first_var_label is only applicable when use_category_labels is True.554 Specifying a set label when use_first_var_label is True might result in an invalid mrset definition.555 Examples556 --------557 Category (C) Set::558 {"$mc_mrset": {559 "label": "This is an MC set",560 "variable_list": ["var1", "var2", "var3"]561 }}562 Dichotomous (D) Set::563 {"$md_mrset": {564 "label": "This is an MD set",565 "counted_value": 1,566 "variable_list": ["resp1", "resp2", "resp3"]567 }}568 Dichotomous (E - Extended) Set::569 {"$md_mrset": {570 "counted_value": 1,571 "use_category:labels": True,572 "use_first_var_label": True,573 "variable_list": ["cat1", "cat2", "cat3"]574 }}575 """576 mrsets_dict = {}577 func = self.spssio.spssGetMultRespDefsEx578 func.argtypes = [c_int, POINTER(c_char_p)]579 mrsets_string = c_char_p()580 retcode = func(self.fh, mrsets_string)581 if retcode > 0:582 self.spssio.spssFreeMultRespDefs(mrsets_string)583 warn_or_raise(retcode, func)584 elif mrsets_string:585 mrsets = mrsets_string.value.decode(self.encoding) # pylint: disable=no-member586 mrsets = mrsets.strip().split("\n")587 mrsets = [x.split("=", 1) for x in mrsets]588 for mrset in mrsets:589 d = {}590 setname, attr = mrset591 if attr[0].upper() == "C":592 mrsets_dict[setname] = self._parse_mrset_c(attr)593 elif attr[0].upper() == "D":594 mrsets_dict[setname] = self._parse_mrset_d(attr)595 elif attr[0].upper() == "E":596 mrsets_dict[setname] = self._parse_mrset_e(attr)597 # clean598 self.spssio.spssFreeMultRespDefs(mrsets_string)599 warn_or_raise(retcode, func)600 if len(mrsets_dict):601 var_types = self.var_types602 for mrset, d in mrsets_dict.items():603 if d["counted_value"] is not None and var_types[d["variable_list"][0]] == 0:604 d["counted_value"] = int(d["counted_value"])605 return mrsets_dict606 @mrsets.setter607 def mrsets(self, mrsets: dict):608 for mrset_name, mrset_attr in mrsets.items():609 self._add_mrset(mrset_name, mrset_attr)610 def _add_mrset(self, mrset_name: str, mrset_attr: dict) -> None:611 var_types = self.var_types612 is_dichotomy = mrset_attr.get("is_dichotomy")613 counted_value = mrset_attr.get("counted_value")614 # infer is_dichotomy when not explicitly specified615 if is_dichotomy is None:616 is_dichotomy = counted_value is not None617 # determine if set is numeric618 is_numeric = isinstance(counted_value, (int, float))619 encoded_vars = []620 for var in mrset_attr.get("variable_list", []):621 if var in var_types:622 encoded_vars.append(var.encode(self.encoding))623 num_vars = len(encoded_vars)624 class MRSetStruct(Structure):625 pass626 MRSetStruct._fields_ = [627 ("szMrSetName", c_char * int((SPSS_MAX_VARNAME + 1))),628 ("szMrSetLabel", c_char * int((SPSS_MAX_VARLABEL + 1))),629 ("qIsDichotomy", c_int),630 ("qIsNumeric", c_int),631 ("qUseCategoryLabels", c_int),632 ("qUseFirstVarLabel", c_int),633 ("Reserved", c_int * 14),634 ("nCountedValue", c_long),635 ("pszCountedValue", c_char_p),636 ("ppszVarNames", POINTER(c_char_p * num_vars)),637 ("nVariables", c_int),638 ]639 func = self.spssio.spssAddMultRespDefExt640 func.argtypes = [c_int, POINTER(MRSetStruct)]641 set_name = mrset_name.encode(self.encoding)642 set_label = mrset_attr.get("label", "").encode(self.encoding)643 is_dichotomy = int(is_dichotomy)644 is_numeric = int(is_numeric)645 use_category_labels = int(is_dichotomy and mrset_attr.get("use_category_labels", False))646 use_first_var_label = int(647 is_dichotomy and use_category_labels and mrset_attr.get("use_first_var_label", False)648 )649 reserved = (c_int * 14)(0)650 n_counted_value = 0 if not is_numeric else int(counted_value)651 c_counted_value = ("" if (is_numeric or not is_dichotomy) else counted_value).encode(652 self.encoding653 )654 var_names = (c_char_p * num_vars)(*encoded_vars)655 args = (656 set_name,657 set_label,658 is_dichotomy,659 is_numeric,660 use_category_labels,661 use_first_var_label,662 reserved,663 n_counted_value,664 c_counted_value,665 pointer(var_names),666 num_vars,667 )668 mrset_struct = MRSetStruct(*args)669 retcode = func(self.fh, byref(mrset_struct))670 warn_or_raise(retcode, func, (mrset_name, mrset_attr, args))671 @property672 def case_size(self) -> int:673 """Record case size (in bytes)674 Raw number of bytes for a single case record.675 It can be calculated manually by adding all variable types676 rounded up to the nearest multiple of 8.677 This is the buffer size used to read a whole case record at once.678 It is not necessily the number of bytes used to store a679 case record on disk (depending on compression).680 """681 func = self.spssio.spssGetCaseSize682 func.argtypes = [c_int, POINTER(c_long)]683 case_size = c_long()684 retcode = func(self.fh, case_size)685 warn_or_raise(retcode, func)686 return case_size.value687 @property688 def case_weight_var(self) -> str:689 """Case weight variable690 Variable set as the "weight" variable in SPSS.691 Must be a scale numeric variable.692 """693 func = self.spssio.spssGetCaseWeightVar694 case_weight_var = create_string_buffer(SPSS_MAX_VARNAME + 1)695 retcode = func(self.fh, case_weight_var)696 warn_or_raise(retcode, func)697 return case_weight_var.value.decode(self.encoding)698 @case_weight_var.setter699 def case_weight_var(self, var_name: str):700 func = self.spssio.spssSetCaseWeightVar701 func.argtypes = [c_int, c_char_p]702 retcode = func(self.fh, var_name.encode(self.encoding))703 warn_or_raise(retcode, func, var_name)704 def _get_var_n_missing_values(self, var_name):705 func = self.spssio.spssGetVarNMissingValues706 func.argtypes = [707 c_int,708 c_char_p,709 POINTER(c_int),710 POINTER(c_double),711 POINTER(c_double),712 POINTER(c_double),713 ]714 missing_format = c_int()715 val_1, val_2, val_3 = c_double(), c_double(), c_double()716 retcode = func(717 self.fh, var_name.encode(self.encoding), missing_format, val_1, val_2, val_3718 )719 warn_or_raise(retcode, func, var_name)720 missing_format = missing_format.value721 missing_values = [val_1.value, val_2.value, val_3.value]722 return (missing_format, missing_values)723 def _get_var_c_missing_values(self, var_name, var_type):724 """Will not return missing values if variable type > 8 (ex. A25)"""725 func = self.spssio.spssGetVarCMissingValues726 func.argtypes = [c_int, c_char_p, POINTER(c_int), c_char_p, c_char_p, c_char_p]727 missing_format = c_int()728 val_1 = create_string_buffer(var_type + 1)729 val_2 = create_string_buffer(var_type + 1)730 val_3 = create_string_buffer(var_type + 1)731 retcode = func(732 self.fh, var_name.encode(self.encoding), missing_format, val_1, val_2, val_3733 )734 warn_or_raise(retcode, func, var_name)735 missing_format = missing_format.value736 missing_values = [737 val_1.value.decode(self.encoding).rstrip(),738 val_2.value.decode(self.encoding).rstrip(),739 val_3.value.decode(self.encoding).rstrip(),740 ]741 return (missing_format, missing_values)742 @property743 def var_missing_values(self) -> dict:744 """Missing values745 Missing value definitions may contain three keys746 1. lo = Low value used in missing range747 2. hi = high value used in missing range748 3. values = list of discrete values set as user missing749 For missing ranges, the following keywords can be used inplace of numeric values750 - low = -inf, lo, low, lowest751 - high = inf, hi, high, highest752 """753 var_missing_values = {}754 for var_name, var_type in self.var_types.items():755 if var_type:756 missing_format, missing_values = self._get_var_c_missing_values(var_name, var_type)757 else:758 missing_format, missing_values = self._get_var_n_missing_values(var_name)759 if missing_format == SPSS_NO_MISSVAL:760 var_missing_values[var_name] = None761 elif missing_format in [SPSS_ONE_MISSVAL, SPSS_TWO_MISSVAL, SPSS_THREE_MISSVAL]:762 var_missing_values[var_name] = {"values": missing_values[:missing_format]}763 elif missing_format in [SPSS_MISS_RANGE, SPSS_MISS_RANGEANDVAL]:764 low, high = missing_values[:2]765 low = float("-inf") if low <= self.low_value else low766 high = float("inf") if high >= self.high_value else high767 var_missing_values[var_name] = {"lo": low, "hi": high}768 if missing_format == SPSS_MISS_RANGEANDVAL:769 var_missing_values[var_name]["values"] = missing_values[2:3]770 return {k: v for k, v in var_missing_values.items() if v}771 @var_missing_values.setter772 def var_missing_values(self, var_missing_values: dict):773 var_types = self.var_types774 for var_name, missing_values in var_missing_values.items():775 var_type = var_types.get(var_name)776 if var_type:777 func = self.spssio.spssSetVarCMissingValues778 func.argtypes = [c_int, c_char_p, c_int, c_char_p, c_char_p, c_char_p]779 discrete_values = missing_values.get("values", [])780 missing_format = min(3, len(discrete_values))781 val_1 = "" if missing_format < SPSS_ONE_MISSVAL else discrete_values[0]782 val_2 = "" if missing_format < SPSS_TWO_MISSVAL else discrete_values[1]783 val_3 = "" if missing_format < SPSS_THREE_MISSVAL else discrete_values[2]784 retcode = func(785 self.fh,786 var_name.encode(self.encoding),787 c_int(missing_format),788 val_1.encode(self.encoding),789 val_2.encode(self.encoding),790 val_3.encode(self.encoding),791 )792 warn_or_raise(retcode, func, var_name)793 elif var_type == 0:794 func = self.spssio.spssSetVarNMissingValues795 func.argtypes = [c_int, c_char_p, c_int, c_double, c_double, c_double]796 low = missing_values.get("lo")797 high = missing_values.get("hi")798 discrete_values = missing_values.get("values", [])799 if low is not None and high is not None:800 if str(low) in ["-inf", "lo", "low", "lowest"] or low <= self.low_value:801 low = self.low_value802 if str(high) in ["inf", "hi", "high", "highest"] or high >= self.high_value:803 high = self.high_value804 val_1 = low805 val_2 = high806 if len(discrete_values):807 missing_format = SPSS_MISS_RANGEANDVAL808 val_3 = discrete_values[0]809 else:810 missing_format = SPSS_MISS_RANGE811 val_3 = self.sysmis812 else:813 missing_format = min(3, len(discrete_values))814 val_1 = (815 self.sysmis if missing_format < SPSS_ONE_MISSVAL else discrete_values[0]816 )817 val_2 = (818 self.sysmis if missing_format < SPSS_TWO_MISSVAL else discrete_values[1]819 )820 val_3 = (821 self.sysmis if missing_format < SPSS_THREE_MISSVAL else discrete_values[2]822 )823 retcode = func(824 self.fh,825 var_name.encode(self.encoding),826 c_int(missing_format),827 c_double(val_1),828 c_double(val_2),829 c_double(val_3),830 )831 warn_or_raise(retcode, func, var_name)832 def _get_var_attributes(self, var_name):833 """Get attributes for a single variable"""834 func = self.spssio.spssGetVarAttributes835 clean = self.spssio.spssFreeAttributes836 def func_config(array_size=0):837 argtypes = [838 c_int,839 c_char_p,840 POINTER(POINTER(c_char_p * array_size)),841 POINTER(POINTER(c_char_p * array_size)),842 POINTER(c_int),843 ]844 attr_names = POINTER(c_char_p * array_size)()845 attr_text = POINTER(c_char_p * array_size)()846 num_attributes = c_int()847 return argtypes, attr_names, attr_text, num_attributes848 # first get initial size849 argtypes, attr_names, attr_text, num_attributes = func_config()850 func.argtypes = argtypes851 retcode = func(852 self.fh, var_name.encode(self.encoding), attr_names, attr_text, num_attributes853 )854 warn_or_raise(retcode, func)855 # get actual array size and clean856 array_size = num_attributes.value857 retcode = clean(attr_names, attr_text, num_attributes)858 warn_or_raise(retcode, clean)859 if array_size == 0:860 return {}861 else:862 # get attributes863 argtypes, attr_names, attr_text, num_attributes = func_config(array_size)864 func.argtypes = argtypes865 retcode = func(866 self.fh, var_name.encode(self.encoding), attr_names, attr_text, num_attributes867 )868 warn_or_raise(retcode, func)869 # clean870 retcode = clean(attr_names, attr_text, num_attributes)871 warn_or_raise(retcode, clean)872 attr_names = (x.decode(self.encoding) for x in attr_names[0])873 attr_text = (x.decode(self.encoding) for x in attr_text[0])874 return dict(zip(attr_names, attr_text))875 @property876 def var_attributes(self) -> dict:877 """Variable attributes878 These are arbitrary variable properties,879 analagous to file attributes"""880 var_attributes = {}881 for var_name in self.var_names:882 attributes = self._get_var_attributes(var_name)883 if attributes:884 var_attributes[var_name] = attributes885 return var_attributes886 @var_attributes.setter887 def var_attributes(self, var_attributes: dict):888 func = self.spssio.spssSetVarAttributes889 for var_name, attributes in var_attributes.items():890 array_size = len(attributes)891 attr_names = []892 attr_text = []893 for name, text in attributes.items():894 attr_names.append(str(name).encode(self.encoding))895 attr_text.append(str(text).encode(self.encoding))896 attr_names = (c_char_p * array_size)(*attr_names)897 attr_text = (c_char_p * array_size)(*attr_text)898 func.argtypes = [899 c_int,900 c_char_p,901 POINTER(c_char_p * array_size),902 POINTER(c_char_p * array_size),903 c_int,904 ]905 retcode = func(906 self.fh, var_name.encode(self.encoding), attr_names, attr_text, array_size907 )908 warn_or_raise(retcode, func, var_name)909 def _get_var_compat_name(self, var_name):910 "Returns 8 byte compatible variable name"911 func = self.spssio.spssGetVarCompatName912 func.argtypes = [c_int, c_char_p, c_char_p]913 var_compat_name = create_string_buffer(SPSS_MAX_SHORTVARNAME + 1)914 retcode = func(self.fh, var_name.encode(self.encoding), var_compat_name)915 warn_or_raise(retcode, func, var_name)916 return var_compat_name.value.decode(self.encoding).strip()917 @property918 def var_compat_names(self) -> dict:919 """Short (8-byte) variable names920 Dictionary of variable names with their "compatible" short 8-byte counterparts921 """922 var_compat_names = {}923 for var_name in self.var_names:924 var_compat_names[var_name] = self._get_var_compat_name(var_name)925 return var_compat_names926 @property927 def var_sets(self) -> dict:928 """Variable sets929 These are NOT multi response sets. These variable sets are groupings930 of variables that can be selected in the SPSS application as a sort of view filter.931 SPSS apparently may use the 8 byte compatible variable names for this property.932 It's currently not possible to obtain the auto-generated compatible names933 until the dictionary is committed, which means setting this property potentially934 requires first comitting a dictionary with all variables, and then rewriting it935 after obtaining the compatible variable names.936 Set names when created in the normal SPSS application allow spaces and special characters.937 However, The I/O module returns an SPSS_INVALID_VARSETDEF error when these are included.938 When an "=" sign is included in the set name, the set name is truncated.939 """940 short_to_long_var_names = {941 var_compat_name: var_name942 for var_name, var_compat_name in self.var_compat_names.items()943 }944 func = self.spssio.spssGetVariableSets945 clean = self.spssio.spssFreeVariableSets946 func.argtypes = [c_int, POINTER(c_char_p)]947 var_sets_string = c_char_p()948 retcode = func(self.fh, var_sets_string)949 warn_or_raise(retcode, func)950 var_sets_dict = {}951 if retcode not in [SPSS_NO_VARSETS, SPSS_EMPTY_VARSETS]:952 var_sets = var_sets_string.value.decode(self.encoding) # pylint: disable=no-member953 var_sets = var_sets.strip().split("\n")954 for var_set in var_sets:955 try:956 set_name, var_list = var_set.split("=", maxsplit=1)957 except ValueError:958 pass959 else:960 var_list = var_list.strip().split()961 var_sets_dict[set_name] = [962 short_to_long_var_names.get(var, var) for var in var_list963 ]964 retcode = clean(var_sets_string)965 warn_or_raise(retcode, clean)966 return var_sets_dict967 @var_sets.setter968 def var_sets(self, var_sets: dict):969 if not var_sets:970 return971 func = self.spssio.spssSetVariableSets972 func.argtypes = [c_int, c_char_p]973 var_set_defs = []974 for set_name, var_list in var_sets.items():975 set_name_fixed = set_name if "=" not in set_name else set_name[: set_name.find("=")]976 var_list_string = " ".join(var_list)977 var_set_defs.append(f"{set_name_fixed}= {var_list_string}")978 var_sets_string = "\n".join(var_set_defs)979 retcode = func(self.fh, var_sets_string.encode(self.encoding))980 warn_or_raise(retcode, func)981 def commit_header(self):982 """Finalize metadata983 This function is used to finalize the header information before writing data.984 Once this function is called, no further metadata modification is allowed.985 """986 func = self.spssio.spssCommitHeader987 retcode = func(self.fh)...

Full Screen

Full Screen

spssfile.py

Source:spssfile.py Github

copy

Full Screen

...148 def interface_encoding(self, unicode: bool):149 func = self.spssio.spssSetInterfaceEncoding150 func.argtypes = [c_int]151 retcode = func(c_int(int(unicode)))152 warn_or_raise(retcode, func)153 return154 @property155 def file_encoding(self) -> str:156 """File encoding reported by I/O module"""157 func = self.spssio.spssGetFileEncoding158 psz_encoding = create_string_buffer(SPSS_MAX_ENCODING + 1)159 retcode = func(self.fh, psz_encoding)160 warn_or_raise(retcode, func)161 return psz_encoding.value.decode(self.encoding)162 def set_locale(self, locale: str) -> str:163 """Set I/O module to a specific locale"""164 func = self.spssio.spssSetLocale165 func.argtypes = [c_int, c_char_p]166 func.restype = c_char_p167 result = func(lc.LC_ALL, locale.encode(self.encoding))168 if result:169 return result.decode(self.encoding)170 else:171 warnings.warn(172 "Failed to set locale to: "173 + locale174 + ". "175 + "Current locale is: "176 + ".".join(lc.getlocale()),177 stacklevel=2,178 )179 return ".".join(lc.getlocale())180 @property181 def is_compatible_encoding(self) -> bool:182 """Check encoding compatibility183 From I/O module documentation: "This function determines whether the file's encoding is compatible with the current interface encoding.184 The result value ... will be false when reading a code page file in UTF-8 mode, when reading185 a UTF-8 file in code page mode when reading a code page file encoded in other than the current locale's186 code page, or when reading a file with numbers represented in reverse bit order. If the encoding is187 incompatible, data stored in the file by other applications, particularly Data Entry for Windows, may be188 unreliable."189 """190 func = self.spssio.spssIsCompatibleEncoding191 func.argtypes = [c_int, POINTER(c_int)]192 b_compatible = c_int()193 retcode = func(self.fh, b_compatible)194 warn_or_raise(retcode, func)195 return bool(b_compatible.value)196 def open(self) -> int:197 """Open file198 Returns file handle that is used for most other I/O module functions.199 Notes200 -----201 Filenames are always encoded in UTF-8 regardless of interface mode and locale settings.202 This is to avoid issues where a filename uses special characters that aren't available203 in the encoding defined by the file itself. For example, a Windows-1252 .sav file204 which uses Chinese (or other special multibyte characters) in its filename.205 """206 with open(self.filename, self.mode) as f:207 fh = c_int(f.fileno())208 filename_adjusted = os.path.expanduser(os.path.abspath(self.filename))209 filename_encoded = filename_adjusted.encode("utf-8")210 func = self._modes[self.mode]["open"]211 retcode = func(filename_encoded, byref(fh))212 warn_or_raise(retcode, func)213 return fh214 def close(self):215 """Close file"""216 func = self._modes[self.mode]["close"]217 retcode = func(self.fh)218 warn_or_raise(retcode, func)219 @property220 def compression(self) -> int:221 """Compression level222 - 0 = No compression223 - 1 = SAV224 - 2 = ZSAV225 """226 func = self.spssio.spssGetCompression227 func.argtypes = [c_int, POINTER(c_int)]228 comp_switch = c_int()229 retcode = func(self.fh, comp_switch)230 warn_or_raise(retcode, func)231 return comp_switch.value232 @compression.setter233 def compression(self, comp_switch=1):234 func = self.spssio.spssSetCompression235 retcode = func(self.fh, c_int(comp_switch))236 warn_or_raise(retcode, func)237 @property238 def release_info(self) -> dict:239 """Basic file information240 - release number241 - release subnumber242 - fixpack number243 - machine code244 - floating-point representation code245 - compression scheme code246 - big/little-endian code247 - character representation code248 """249 fields = [250 "release number",251 "release subnumber",252 "fixpack number",253 "machine code",254 "floating-point representation code",255 "compression scheme code",256 "big/little-endian code",257 "character representation code",258 ]259 rel_info_arr = (c_int * len(fields))()260 func = self.spssio.spssGetReleaseInfo261 retcode = func(self.fh, rel_info_arr)262 warn_or_raise(retcode, func)263 return dict([(item, rel_info_arr[i]) for i, item in enumerate(fields)])264 @property265 def var_count(self) -> int:266 """Number of variables"""267 func = self.spssio.spssGetNumberofVariables268 func.argtypes = [c_int, POINTER(c_long)]269 num_vars = c_long()270 retcode = func(self.fh, num_vars)271 warn_or_raise(retcode, func)272 return num_vars.value273 @property274 def case_count(self) -> int:275 """Number of cases"""276 func = self.spssio.spssGetNumberofCases277 func.argtypes = [c_int, POINTER(c_long)]278 num_cases = c_long()279 retcode = func(self.fh, num_cases)280 warn_or_raise(retcode, func)...

Full Screen

Full Screen

writer.py

Source:writer.py Github

copy

Full Screen

...41 """case_record is a string buffer"""42 func = self.spssio.spssWholeCaseOut43 func.argtypes = [c_int, c_char_p]44 retcode = func(self.fh, case_record)45 warn_or_raise(retcode, func)46 def _set_value_char(self, var_name, value):47 var_handle = self._get_var_handle(var_name.encode(self.encoding))48 func = self.spssio.spssSetValueChar49 func.argtypes = [c_int, c_double, c_char_p]50 retcode = func(self.fh, var_handle, value)51 warn_or_raise(retcode, func, var_name, value)52 def _set_value_numeric(self, var_name, value):53 var_handle = self._get_var_handle(var_name.encode(self.encoding))54 func = self.spssio.spssSetValueNumeric55 func.argtypes = [c_int, c_double, c_double]56 retcode = func(self.fh, var_handle, value)57 warn_or_raise(retcode, func, var_name, value)58 def commit_case_record(self):59 """Commit case record60 Call function after setting values with set_value61 Do not use with whole_case_out"""62 func = self.spssio.spssCommitCaseRecord63 retcode = func(self.fh)64 warn_or_raise(retcode, func)65 def write_header(self, df: DataFrame, metadata: Union[dict, SimpleNamespace] = None, **kwargs):66 """Write metadata properties67 Parameters68 ----------69 df70 DataFrame71 metadata72 Dictionary of Header attributes to use (see Header class for more detail)73 **kwargs74 Additional arguments, including individual metadata attributes.75 Note that metadata attributes supplied here take precedence.76 """77 compression = {".sav": 1, ".zsav": 2}.get(os.path.splitext(self.filename)[1].lower())78 self.compression = compression79 if metadata is None:80 metadata = {}81 elif isinstance(metadata, SimpleNamespace):82 metadata = metadata.__dict__83 # combine, with preference to kwargs84 metadata = {**metadata, **kwargs}85 metadata["var_types"] = metadata.get("var_types", {})86 metadata["var_formats"] = metadata.get("var_formats", {})87 metadata["var_measure_levels"] = metadata.get("var_measure_levels", {})88 # convert all var_formats to tuple structure89 # ignore var_formats_tuple if supplied90 # var_formats can be either plain or tuple structure91 metadata["var_formats"] = {92 var_name: varformat_to_tuple(var_format)93 for var_name, var_format in metadata["var_formats"].items()94 }95 dtypes = df.dtypes.to_dict()96 var_types = {}97 encoding = self.encoding98 # setup types, formats, levels99 for col, dtype in dtypes.items():100 if (101 metadata["var_types"].get(col)102 or is_string_dtype(dtypes.get(col))103 or is_object_dtype(dtypes.get(col))104 ):105 var_type = (106 df[col]107 .fillna("")108 .apply(lambda x: (x if hasattr(x, "decode") else len(str(x).encode(encoding))))109 .max()110 )111 var_type = max(var_type, metadata["var_types"].get(col, 1))112 var_type = min(var_type, SPSS_MAX_LONGSTRING)113 var_types[col] = var_type114 var_format = metadata["var_formats"].get(col, (1, 1, 0))115 metadata["var_formats"][col] = (116 var_format[0] if var_format[0] in spss_string_formats else 1,117 var_type,118 0,119 )120 elif is_timedelta64_dtype(dtype):121 var_types[col] = 0122 metadata["var_formats"][col] = metadata["var_formats"].get(123 col, config.default_time_format124 )125 metadata["var_measure_levels"][col] = metadata["var_measure_levels"].get(col, 3)126 elif is_datetime64_any_dtype(dtype):127 var_types[col] = 0128 metadata["var_formats"][col] = metadata["var_formats"].get(129 col, config.default_datetime_format130 )131 metadata["var_measure_levels"][col] = metadata["var_measure_levels"].get(col, 3)132 else:133 var_types[col] = 0134 metadata["var_formats"][col] = metadata["var_formats"].get(135 col, config.default_numeric_format136 )137 metadata["var_measure_levels"][col] = metadata["var_measure_levels"].get(col, 3)138 # initiate variables139 for col in df.columns:140 self._add_var(col, var_types[col])141 # set optional header attributes142 attr_to_ignore = [143 "case_count",144 "encoding",145 "var_names",146 "var_types",147 "var_formats_tuple",148 "var_compat_names",149 ]150 attrs = [attr for attr in dir(self) if attr[0] != "_" and attr not in attr_to_ignore]151 # catch Exceptions for non-critical attributes152 failed_to_set = {}153 for attr, v in metadata.items():154 if attr in attrs and v:155 try:156 setattr(self, attr, v)157 except SPSSError as e:158 failed_to_set[attr] = e159 if failed_to_set:160 warnings.warn(161 SPSSWarning(162 "Errors occurred while writing header attributes:\n\n"163 + "\n\n".join((f"{attr}: {error}" for attr, error in failed_to_set.items()))164 + "\n"165 ),166 stacklevel=2,167 )168 # commit header169 self.commit_header()170 def write_data_by_val(self, df: DataFrame):171 """Write data by variable/value172 Parameters173 ----------174 df175 DataFrame176 Notes177 -----178 Slower than whole_case_out179 Use when appending to an existing data set and variable order doesn't align180 """181 pd_origin = pd.to_datetime(0)182 var_types = self.var_types183 var_handles = self.var_handles184 dtypes = df.dtypes.to_dict()185 idx_cols = dict(enumerate(df.columns))186 write_c = self.spssio.spssSetValueChar187 write_c.argtypes = [c_int, c_double, c_char_p]188 write_n = self.spssio.spssSetValueNumeric189 write_n.argtypes = [c_int, c_double, c_double]190 for row in df.itertuples(index=False, name=None):191 for idx, col in idx_cols.items():192 value = row[idx]193 if pd.notna(value):194 # string195 if var_types[col]:196 value = value.encode(self.encoding)197 retcode = write_c(self.fh, var_handles[col], value)198 warn_or_raise(retcode, write_c, col, value)199 # time200 elif is_timedelta64_dtype(dtypes[col]):201 value = value.total_seconds()202 retcode = write_n(self.fh, var_handles[col], value)203 warn_or_raise(retcode, write_n, col, value)204 # datetime205 elif is_datetime64_any_dtype(dtypes[col]):206 value = (value - pd_origin).total_seconds() + SPSS_ORIGIN_OFFSET207 retcode = write_n(self.fh, var_handles[col], value)208 warn_or_raise(retcode, write_n, col, value)209 # numeric210 else:211 retcode = write_n(self.fh, var_handles[col], value)212 warn_or_raise(retcode, write_n, col, value)213 self.commit_case_record()214 def write_data(self, df: DataFrame, **kwargs):215 """Write data to file216 Parameters217 ----------218 df219 DataFrame220 """221 # basic info222 var_types = self.var_types223 sysmis = self.sysmis224 encoding = self.encoding225 pd_origin = pd.to_datetime(0)226 def get_buffer_size(var_type):...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run lisa automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful