def _get_case_attr_default_value(value: attr.Attribute) -> str: """Return the default value of a CaseDescription.""" if value.default == attr.NOTHING: return "" default_value_string = " = " if isinstance(value.default, enum.Enum): default_value_string += ( f"{value.default.__class__.__name__}.{value.default.name}") elif isinstance(value.default, attr.Factory): if value.default.factory is dict: default_value_string += "{}" elif value.default.factory is list: default_value_string += "[]" elif is_attrs(value.default.factory): default_value_string += f"{value.default.factory.__name__}()" else: assert False, "Unknown factory" # pragma: no cover elif is_attrs(value.default): default_value_string += f"{value.default.__class__.__name__}()" else: default_value_string += f"{repr(value.default)}" return default_value_string
def list_formatted(value: Any) -> str: """ Return a string with a cross-referencing link for the List class and to the refer type. """ name = value.__args__[0].__name__ list_with_ref = _get_list_reference() if is_attrs(value.__args__[0]): name = attrs_formatted(value.__args__[0]) return f"{list_with_ref}[{name}]"
def list_formatted_for_schema(value: Any) -> str: """ Return a string showing a list with the parameters used, if the parameter is an attrs class, a cross-referencing link will be added. """ block_indentation = BASE_INDENT + INDENT argument = value.__args__[0] if is_attrs(argument): return f"\n{block_indentation}- {attrs_formatted_for_schema(argument)}" return f"\n{block_indentation}- {argument.__name__}"
def dict_formatted(value: Any) -> str: """ Return a string with a cross-referencing link for the Dict class and to the refer type. """ dict_with_reference = _get_dict_reference() referenced_value = value.__args__[1] if is_attrs(referenced_value): name = attrs_formatted(referenced_value) elif is_scalar(referenced_value): name = _get_scalar_reference() elif is_array(referenced_value): name = _get_array_reference() else: name = str(referenced_value).replace("typing.", "") return f"{dict_with_reference}[str, {name}]"
def convert_dict_to_valid_alfacase_format( case_description_dict: Dict[str, ATTRIBUTES], enable_flow_style_on_numpy: bool) -> Dict[str, Any]: """ Convert all values of the dictionary to string. Note.: strict_yaml only allows "str" values on all attributes in order to render the YAML content. :param enable_flow_style_on_numpy: Signalize that numpy arrays should dumped with inline list ( pressure: [1, 2] ). """ converted_dict = {} for key, value in case_description_dict.items(): is_empty_dict = isinstance(value, dict) and not value ignore = key in IGNORED_PROPERTIES if is_empty_dict or value is None or ignore: continue if is_attrs(value): to_dict = partial(attr.asdict, recurse=False) if isinstance(value, list): converted_value = [ convert_dict_to_valid_alfacase_format( to_dict(i), enable_flow_style_on_numpy) for i in value ] else: converted_value = convert_dict_to_valid_alfacase_format( to_dict(value), enable_flow_style_on_numpy) if converted_value: converted_dict[key] = converted_value continue if isinstance(value, dict): converted_dict[key] = convert_dict_to_valid_alfacase_format( value, enable_flow_style_on_numpy) continue converted_dict[key] = _convert_value_to_valid_alfacase_format( value, enable_flow_style_on_numpy) return converted_dict
def test_convert_alfacase_to_description(alfacase_to_case_helper, class_, tmp_path): """ Test to convert Alfacase from all classes of alfasim_core.simulation_models.case_description that needs a Alfacase schema """ alfacase_test_config = ALFACASE_TEST_CONFIG_MAP[class_.__name__] file_path = tmp_path / "test_case.alfacase" description_obtained = alfacase_to_case_helper.generate_description( alfacase_test_config ) description_obtained = ( description_obtained[0] if alfacase_test_config.is_sequence else description_obtained ) expected_dict = attr.asdict(alfacase_test_config.description_expected) description_obtained = ( description_obtained if is_attrs(description_obtained) else description_obtained["FakeKey"] ) obtained_dict = attr.asdict(description_obtained) # PvtModels that uses Tables has the full path, while YAML has the partial # The following inject the full path on the expected_dict, in order to test the obtained_dict def fill_pvt_table_path(values): if "pvt_models" in values: fill_pvt_table_path(values["pvt_models"]) elif "tables" in values: for pvt_name in values["tables"]: values["tables"][pvt_name] = ( file_path.parent / values["tables"][pvt_name] ) return values expected_dict = fill_pvt_table_path(expected_dict) # Check that generated test case is correct ensure_descriptions_are_equal(expected_dict, obtained_dict, IGNORED_PROPERTIES) # Ensure that all properties from the original Case is present in the generated test case alfacase_to_case_helper.ensure_description_has_all_properties( expected_description_class=class_, obtained_description_obj=description_obtained )
def dict_formatted_for_schema(value: Any) -> str: """ Return a string showing a dict with the parameters used, if the parameter is class that has a sphinx reference (attr, Scalar, Array) a cross-referencing link will be added. """ lines = f"\n{BASE_INDENT + INDENT}" lines += "string: " argument = value.__args__[1] if is_attrs(argument): lines += attrs_formatted_for_schema(argument) elif is_union(argument): lines += f"{' | '.join(i.__name__.replace('str', 'string') for i in argument.__args__)}" elif is_scalar(argument): lines += scalar_formatted_for_schema(argument, number_of_indent=2) elif is_array(argument): lines += array_formatted_for_schema(argument, number_of_indent=2) else: lines += argument.__name__ return lines
def union_formatted_for_schema(value: Any) -> str: """ All usages of union on CaseDescription are from the Optional module, so this function will return a string showing parameters with a label '# optional' indicating that this field could be is not mandatory. """ parameter = value.__args__[0] if value.__args__ in ((str, type(None)), (Path, type(None))): name = "string" elif value.__args__ == (Array, type(None)): name = f"{INDENT}" name += array_formatted_for_schema(value) elif isinstance(parameter, enum.EnumMeta): name = f"{enum_formatted_for_schema(parameter)}" elif is_attrs(parameter): name = f"{attrs_formatted_for_schema(parameter)}" elif is_list(parameter): name = f"{INDENT}" name += list_formatted_for_schema(parameter) else: name = str(value).replace("typing.", "") return name
def convert_dict_to_valid_alfacase_format( case_description_dict: Dict[str, ATTRIBUTES], *, enable_flow_style_on_numpy: bool, remove_redundant_input_type_data: bool = True, ) -> Dict[str, Any]: """ Convert all values of the dictionary to string. Note.: strict_yaml only allows "str" values on all attributes in order to render the YAML content. :param enable_flow_style_on_numpy: Signalize that numpy arrays should dumped with inline list ( pressure: [1, 2] ). :param remove_redundant_input_type_data: For transient entries remove input type selector, and the unused constant or curve entries. """ transient_fields: Dict[str, MultiInputType] = {} converted_dict = {} for key, value in case_description_dict.items(): is_empty_dict = isinstance(value, dict) and not value ignore = key in IGNORED_PROPERTIES if is_empty_dict or value is None or ignore: continue if remove_redundant_input_type_data and isinstance( value, constants.MultiInputType): assert key.endswith(constants.MULTI_INPUT_TYPE_SUFFIX) transient_fields[key] = value if is_attrs(value): to_dict = partial(attr.asdict, recurse=False) if isinstance(value, list): converted_value = [ convert_dict_to_valid_alfacase_format( to_dict(i), enable_flow_style_on_numpy=enable_flow_style_on_numpy, remove_redundant_input_type_data= remove_redundant_input_type_data, ) for i in value ] else: converted_value = convert_dict_to_valid_alfacase_format( to_dict(value), enable_flow_style_on_numpy=enable_flow_style_on_numpy, remove_redundant_input_type_data= remove_redundant_input_type_data, ) if converted_value: converted_dict[key] = converted_value continue if isinstance(value, dict): converted_dict[key] = convert_dict_to_valid_alfacase_format( value, enable_flow_style_on_numpy=enable_flow_style_on_numpy, remove_redundant_input_type_data= remove_redundant_input_type_data, ) continue converted_dict[key] = _convert_value_to_valid_alfacase_format( value, enable_flow_style_on_numpy) if remove_redundant_input_type_data: for key, multi_input_type in transient_fields.items(): constant_key = key[:-len(constants.MULTI_INPUT_TYPE_SUFFIX)] curve_key = f"{constant_key}_curve" converted_dict.pop(key, None) if multi_input_type == constants.MultiInputType.Constant: converted_dict.pop(curve_key, None) elif multi_input_type == constants.MultiInputType.Curve: converted_dict.pop(constant_key, None) else: # pragma: no cover raise AssertionError( f"unexpected value {key}: {multi_input_type}") return converted_dict