def test_cast_ast_eval_true_int(self): # Given data = 123 # When result = utility.cast(data, ast_eval=True) result_str = utility.cast(str(data), ast_eval=True) # Then assert result == data assert result_str == data
def test_cast_ast_eval_false_list(self): # Given data = [1, 2, 3] # When result = utility.cast(data, ast_eval=False) result_str = utility.cast(str(data), ast_eval=False) # Then assert result == str(data) assert result_str == str(data)
def test_cast_ast_eval_true_str(self): # Given data = "abc" # When result = utility.cast(data, ast_eval=True) # Then assert result == data
def _create_compass_dict(form_tree: html.FormElement) -> dict: """Create Compass info dict from FormElement.""" compass_dict = {} compass_vars = form_tree.fields["ctl00$_POST_CTRL"] for pair in compass_vars.split("~"): key, value = pair.split("#", 1) compass_dict[key] = cast(value) # int or str return compass_dict
def test_maybe_int_int(self): # Given data = 123 # When result = utility.maybe_int(data) result_str = utility.cast(str(data)) # Then assert result == data assert result_str == data
def get_roles_detail( self, role_number: int, response: Union[str, requests.Response] = None ) -> Union[schema.MemberRolePopup, dict]: """Returns detailed data from a given role number. Args: role_number: Role Number to use response: Pre-generated response to use Returns: A dicts mapping keys to the corresponding data from the role detail data. E.g.: {'hierarchy': {'organisation': 'The Scout Association', 'country': '...', 'region': '...', 'county': '...', 'district': '...', 'group': '...', 'section': '...'}, 'details': {'role_number': ..., 'organisation_level': '...', 'birth_date': datetime.datetime(...), 'membership_number': ..., 'name': '...', 'role_title': '...', 'role_start': datetime.datetime(...), 'role_status': '...', 'line_manager_number': ..., 'line_manager': '...', 'ce_check': datetime.datetime(...), 'disclosure_check': '...', 'references': '...', 'appointment_panel_approval': '...', 'commissioner_approval': '...', 'committee_approval': '...'}, 'getting_started': {...: {'name': '...', 'validated': datetime.datetime(...), 'validated_by': '...'}, ... }} Keys will always be present. Todo: Other possible exceptions? i.e. from Requests """ # pylint: disable=too-many-locals,too-many-statements renamed_levels = { "County / Area / Scottish Region / Overseas Branch": "County", } renamed_modules = { 1: "module_01", "TRST": "trustee_intro", 2: "module_02", 3: "module_03", 4: "module_04", "GDPR": "GDPR", } unset_vals = {"--- Not Selected ---", "--- No Items Available ---", "--- No Line Manager ---"} module_names = { "Essential Information": "M01", "Trustee Introduction": "TRST", "PersonalLearningPlan": "M02", "Tools for the Role (Section Leaders)": "M03", "Tools for the Role (Managers and Supporters)": "M04", "General Data Protection Regulations": "GDPR", } references_codes = { "NC": "Not Complete", "NR": "Not Required", "RR": "References Requested", "S": "References Satisfactory", "U": "References Unsatisfactory", } start_time = time.time() if response is None: response = self._get(f"{Settings.base_url}/Popups/Profile/AssignNewRole.aspx?VIEW={role_number}") logger.debug(f"Getting details for role number: {role_number}. Request in {(time.time() - start_time):.2f}s") post_response_time = time.time() if isinstance(response, (str, bytes)): tree = html.fromstring(response) else: tree = html.fromstring(response.content) form = tree.forms[0] if form.action == "./ScoutsPortal.aspx?Invalid=Access": raise PermissionError(f"You do not have permission to the details of role {role_number}") member_string = form.fields.get("ctl00$workarea$txt_p1_membername") ref_code = form.fields.get("ctl00$workarea$cbo_p2_referee_status") role_details = dict() # Approval and Role details role_details["role_number"] = role_number role_details["organisation_level"] = form.fields.get("ctl00$workarea$cbo_p1_level") role_details["birth_date"] = parse(form.inputs["ctl00$workarea$txt_p1_membername"].get("data-dob")) role_details["membership_number"] = int(form.fields.get("ctl00$workarea$txt_p1_memberno")) role_details["name"] = member_string.split(" ", maxsplit=1)[1] # TODO does this make sense - should name be in every role?? role_details["role_title"] = form.fields.get("ctl00$workarea$txt_p1_alt_title") role_details["role_start"] = parse(form.fields.get("ctl00$workarea$txt_p1_startdate")) # Role Status role_details["role_status"] = form.fields.get("ctl00$workarea$txt_p2_status") # Line Manager line_manager_el = next((op for op in form.inputs["ctl00$workarea$cbo_p2_linemaneger"] if op.get("selected")), None) role_details["line_manager_number"] = maybe_int(line_manager_el.get("value")) if line_manager_el is not None else None role_details["line_manager"] = line_manager_el.text.strip() if line_manager_el is not None else None # Review Date role_details["review_date"] = parse(form.fields.get("ctl00$workarea$txt_p2_review")) # CE (Confidential Enquiry) Check # TODO if CE check date != current date then is valid role_details["ce_check"] = parse(form.fields.get("ctl00$workarea$txt_p2_cecheck")) # Disclosure Check disclosure_with_date = form.fields.get("ctl00$workarea$txt_p2_disclosure") if disclosure_with_date.startswith("Disclosure Issued : "): disclosure_date = parse(disclosure_with_date.removeprefix("Disclosure Issued : ")) disclosure_check = "Disclosure Issued" else: disclosure_date = None disclosure_check = disclosure_with_date role_details["disclosure_check"] = disclosure_check # TODO extract date role_details["disclosure_date"] = disclosure_date # TODO extract date # References role_details["references"] = references_codes.get(ref_code, ref_code) approval_values = {} for row in tree.xpath("//tr[@class='trProp']"): select = row[1][0] code = select.get("data-app_code") approval_values[code] = select.get("data-db") # select.get("title") gives title text, but this is not useful as it does not reflect latest changes, # but only who added the role to Compass. # Appointment Panel Approval role_details["appointment_panel_approval"] = approval_values.get("ROLPRP|AACA") # Commissioner Approval role_details["commissioner_approval"] = approval_values.get("ROLPRP|CAPR") # Committee Approval role_details["committee_approval"] = approval_values.get("ROLPRP|CCA") if role_details["line_manager_number"] in unset_vals: role_details["line_manager_number"] = None # Filter null values role_details = {k: v for k, v in role_details.items() if v is not None} # Getting Started modules_output = {} getting_started_modules = tree.xpath("//tr[@class='trTrain trTrainData']") # Get all training modules and then extract the required modules to a dictionary for module in getting_started_modules: module_name = module[0][0].text.strip() if module_name in module_names: info = { # "name": module_names[module_name], # short_name "validated": parse(module[2][0].value), # Save module validation date "validated_by": module[1][1].value or None, # Save who validated the module } mod_code = cast(module[2][0].get("data-ng_value")) # int or str modules_output[renamed_modules[mod_code]] = info # Get all levels of the org hierarchy and select those that will have information: # Get all inputs with location data org_levels = [v for k, v in sorted(dict(form.inputs).items()) if "ctl00$workarea$cbo_p1_location" in k] # TODO all_locations = {row.get("title"): row.findtext("./option") for row in org_levels} clipped_locations = { renamed_levels.get(key, key).lower(): value for key, value in all_locations.items() if value not in unset_vals } logger.debug( f"Processed details for role number: {role_number}. " f"Compass: {(post_response_time - start_time):.3f}s; Processing: {(time.time() - post_response_time):.4f}s" ) # TODO data-ng_id?, data-rtrn_id? full_details = { "hierarchy": clipped_locations, "details": role_details, "getting_started": modules_output, } if self.validate: return schema.MemberRolePopup.parse_obj(full_details) else: return full_details