From 950c1b767889d4859e5ea8045d99cb6fcac96546 Mon Sep 17 00:00:00 2001 From: danielfromearth Date: Tue, 19 Sep 2023 13:57:00 -0400 Subject: [PATCH] formatted with ruff+black --- ncompare/console.py | 30 +++- ncompare/core.py | 275 +++++++++++++++++++------------- ncompare/printing.py | 70 +++++--- ncompare/sequence_operations.py | 13 +- ncompare/utils.py | 5 +- 5 files changed, 239 insertions(+), 154 deletions(-) diff --git a/ncompare/console.py b/ncompare/console.py index 15cd38b..39f7142 100755 --- a/ncompare/console.py +++ b/ncompare/console.py @@ -9,20 +9,34 @@ def _cli() -> argparse.Namespace: """Parse input arguments from the command line.""" - parser = argparse.ArgumentParser(description="Compare the variables contained within two different NetCDF datasets") + parser = argparse.ArgumentParser( + description="Compare the variables contained within two different NetCDF datasets" + ) parser.add_argument("nc_a", help="First NetCDF file") parser.add_argument("nc_b", help="First NetCDF file") parser.add_argument("-v", "--comparison_var_name", help="Comparison variable name") parser.add_argument("-g", "--comparison_var_group", help="Comparison variable group") parser.add_argument("--file-text", help="A text file to which the output will be written.") - parser.add_argument("--file-csv", help="A csv (comma separated values) file to which the output will be written.") + parser.add_argument( + "--file-csv", + help="A csv (comma separated values) file to which the output will be written.", + ) parser.add_argument("--file-xlsx", help="An Excel file to which the output will be written.") - parser.add_argument("--no-color", action="store_true", default=False, - help="Turn off all colorized output") - parser.add_argument("--show-attributes", action="store_true", default=False, - help="Include variable attributes in comparison") - parser.add_argument("--show-chunks", action="store_true", default=False, - help="Include chunk sizes in the table that compares variables") + parser.add_argument( + "--no-color", action="store_true", default=False, help="Turn off all colorized output" + ) + parser.add_argument( + "--show-attributes", + action="store_true", + default=False, + help="Include variable attributes in comparison", + ) + parser.add_argument( + "--show-chunks", + action="store_true", + default=False, + help="Include chunk sizes in the table that compares variables", + ) return parser.parse_args() diff --git a/ncompare/core.py b/ncompare/core.py index f78121f..9ae7ddc 100644 --- a/ncompare/core.py +++ b/ncompare/core.py @@ -21,17 +21,19 @@ VarProperties = namedtuple("VarProperties", "varname, variable, dtype, shape, chunking, attributes") -def compare(nc_a: Union[str, Path], - nc_b: Union[str, Path], - comparison_var_group: str = None, - comparison_var_name: str = None, - no_color: bool = False, - show_chunks: bool = False, - show_attributes: bool = False, - file_text: str = None, - file_csv: str = None, - file_xlsx: str = None - ) -> None: + +def compare( + nc_a: Union[str, Path], + nc_b: Union[str, Path], + comparison_var_group: str = None, + comparison_var_name: str = None, + no_color: bool = False, + show_chunks: bool = False, + show_attributes: bool = False, + file_text: str = None, + file_csv: str = None, + file_xlsx: str = None, +) -> None: """Compare the variables contained within two different NetCDF datasets. Parameters @@ -78,12 +80,15 @@ def compare(nc_a: Union[str, Path], out.side_by_side(' ', str(nc_a), str(nc_b)) # Start the comparison process. - run_through_comparisons(out, - nc_a, nc_b, - comparison_var_group=comparison_var_group, - comparison_var_name=comparison_var_name, - show_chunks=show_chunks, - show_attributes=show_attributes) + run_through_comparisons( + out, + nc_a, + nc_b, + comparison_var_group=comparison_var_group, + comparison_var_name=comparison_var_name, + show_chunks=show_chunks, + show_attributes=show_attributes, + ) # Write to CSV and Excel files. if file_csv: @@ -93,13 +98,16 @@ def compare(nc_a: Union[str, Path], out.print("\nDone.", colors=False) -def run_through_comparisons(out: Outputter, - nc_a: Union[str, Path], - nc_b: Union[str, Path], - comparison_var_group: str, - comparison_var_name: str, - show_chunks: bool, - show_attributes: bool) -> None: + +def run_through_comparisons( + out: Outputter, + nc_a: Union[str, Path], + nc_b: Union[str, Path], + comparison_var_group: str, + comparison_var_name: str, + show_chunks: bool, + show_attributes: bool, +) -> None: """Execute a series of comparisons between two NetCDF files. Parameters @@ -125,10 +133,11 @@ def run_through_comparisons(out: Outputter, _, _, _ = out.lists_diff(list_a, list_b) if comparison_var_group: - # Show the variables within the selected group. - out.print(Fore.LIGHTBLUE_EX + "\nVariables within specified group <%s>:" % comparison_var_group, - add_to_history=True) + out.print( + Fore.LIGHTBLUE_EX + "\nVariables within specified group <%s>:" % comparison_var_group, + add_to_history=True, + ) vlist_a = _get_vars(nc_a, comparison_var_group) vlist_b = _get_vars(nc_b, comparison_var_group) _, _, _ = out.lists_diff(vlist_a, vlist_b) @@ -136,18 +145,28 @@ def run_through_comparisons(out: Outputter, if comparison_var_name: try: # Print the first part of the values array for the selected variable. - out.print(Fore.LIGHTBLUE_EX + "\nSample values within specified variable <%s>:" % comparison_var_name) + out.print( + Fore.LIGHTBLUE_EX + + "\nSample values within specified variable <%s>:" % comparison_var_name + ) _print_sample_values(out, nc_a, comparison_var_group, comparison_var_name) _print_sample_values(out, nc_b, comparison_var_group, comparison_var_name) # compare_sample_values(nc_a, nc_b, groupname=comparison_var_group, varname=comparison_var_name) - out.print(Fore.LIGHTBLUE_EX + "\nChecking multiple random values within specified variable <%s>:" - % comparison_var_name) + out.print( + Fore.LIGHTBLUE_EX + + "\nChecking multiple random values within specified variable <%s>:" + % comparison_var_name + ) compare_multiple_random_values(out, nc_a, nc_b, groupname=comparison_var_group) except KeyError: - out.print(Style.BRIGHT + Fore.RED + "\nError when comparing values for variable <%s> in group <%s>." % - (comparison_var_name, comparison_var_group)) + out.print( + Style.BRIGHT + + Fore.RED + + "\nError when comparing values for variable <%s> in group <%s>." + % (comparison_var_name, comparison_var_group) + ) out.print(traceback.format_exc()) out.print("\n") else: @@ -156,13 +175,14 @@ def run_through_comparisons(out: Outputter, out.print(Fore.LIGHTBLACK_EX + "\nNo variable group selected for comparison. Skipping..") out.print(Fore.LIGHTBLUE_EX + "\nAll variables:", add_to_history=True) - _, _, _ = compare_two_nc_files(out, nc_a, nc_b, show_chunks=show_chunks, show_attributes=show_attributes) + _, _, _ = compare_two_nc_files( + out, nc_a, nc_b, show_chunks=show_chunks, show_attributes=show_attributes + ) + -def compare_multiple_random_values(out: Outputter, - nc_a: Path, - nc_b: Path, - groupname: str, - num_comparisons: int = 100): +def compare_multiple_random_values( + out: Outputter, nc_a: Path, nc_b: Path, groupname: str, num_comparisons: int = 100 +): """Iterate through N random samples, and evaluate whether the differences exceed a threshold.""" # Open a variable from each NetCDF nc_var_a = xr.open_dataset(nc_a, backend_kwargs={"group": groupname}).varname @@ -185,11 +205,13 @@ def compare_multiple_random_values(out: Outputter, out.print(Fore.CYAN + " No mismatches.") out.print("Done.", colors=False) -def walk_common_groups_tree(top_a_name: str, - top_a: Union[netCDF4.Dataset, netCDF4.Group], - top_b_name: str, - top_b: Union[netCDF4.Dataset, netCDF4.Group] - ) -> tuple[str, netCDF4.Group, str, netCDF4.Group]: + +def walk_common_groups_tree( + top_a_name: str, + top_a: Union[netCDF4.Dataset, netCDF4.Group], + top_b_name: str, + top_b: Union[netCDF4.Dataset, netCDF4.Group], +) -> tuple[str, netCDF4.Group, str, netCDF4.Group]: """Yield names and groups from a netCDF4's group tree. Parameters @@ -207,74 +229,97 @@ def walk_common_groups_tree(top_a_name: str, group B object : netCDF4.Group """ yield ( - (top_a_name + "/" + group_a_name if group_a_name else "", - top_a[group_a_name] if (group_a_name and (group_a_name in top_a.groups)) else None, - top_b_name + "/" + group_b_name if group_b_name else "", - top_b[group_b_name] if (group_b_name and (group_b_name in top_b.groups)) else None, - ) - for (_, group_a_name, group_b_name) - in common_elements( - top_a.groups if top_a is not None else "", - top_b.groups if top_b is not None else "" + ( + top_a_name + "/" + group_a_name if group_a_name else "", + top_a[group_a_name] if (group_a_name and (group_a_name in top_a.groups)) else None, + top_b_name + "/" + group_b_name if group_b_name else "", + top_b[group_b_name] if (group_b_name and (group_b_name in top_b.groups)) else None, + ) + for (_, group_a_name, group_b_name) in common_elements( + top_a.groups if top_a is not None else "", top_b.groups if top_b is not None else "" ) ) for _, subgroup_a_name, subgroup_b_name in common_elements( - top_a.groups if top_a is not None else "", - top_b.groups if top_a is not None else "" + top_a.groups if top_a is not None else "", top_b.groups if top_a is not None else "" ): yield from walk_common_groups_tree( top_a_name + "/" + subgroup_a_name if subgroup_a_name else "", - top_a[subgroup_a_name] if (subgroup_a_name and (subgroup_a_name in top_a.groups)) else None, + top_a[subgroup_a_name] + if (subgroup_a_name and (subgroup_a_name in top_a.groups)) + else None, top_a_name + "/" + subgroup_b_name if subgroup_b_name else "", - top_b[subgroup_b_name] if (subgroup_b_name and (subgroup_b_name in top_b.groups)) else None + top_b[subgroup_b_name] + if (subgroup_b_name and (subgroup_b_name in top_b.groups)) + else None, ) -def compare_two_nc_files(out: Outputter, - nc_one: Path, - nc_two: Path, - show_chunks: bool = False, - show_attributes: bool = False - ) -> tuple[int, int, int]: + +def compare_two_nc_files( + out: Outputter, + nc_one: Path, + nc_two: Path, + show_chunks: bool = False, + show_attributes: bool = False, +) -> tuple[int, int, int]: """Go through all groups and all variables, and show them side by side - whether they align and where they don't.""" out.side_by_side(' ', 'File A', 'File B') num_var_diffs = {"left": 0, "right": 0, "both": 0} with netCDF4.Dataset(nc_one) as nc_a, netCDF4.Dataset(nc_two) as nc_b: - out.side_by_side('All Variables', ' ', ' ', dash_line=False) out.side_by_side('-', '-', '-', dash_line=True) group_counter = 0 - _print_group_details_side_by_side(out, nc_a, "/", nc_b, "/", group_counter, num_var_diffs, show_attributes, - show_chunks) + _print_group_details_side_by_side( + out, nc_a, "/", nc_b, "/", group_counter, num_var_diffs, show_attributes, show_chunks + ) group_counter += 1 for group_pairs in walk_common_groups_tree("", nc_a, "", nc_b): for group_a_name, group_a, group_b_name, group_b in group_pairs: - - _print_group_details_side_by_side(out, group_a, group_a_name, group_b, group_b_name, group_counter, - num_var_diffs, show_attributes, show_chunks) + _print_group_details_side_by_side( + out, + group_a, + group_a_name, + group_b, + group_b_name, + group_counter, + num_var_diffs, + show_attributes, + show_chunks, + ) group_counter += 1 out.side_by_side('-', '-', '-', dash_line=True) - out.side_by_side('Total number of shared items:', str(num_var_diffs['both']), str(num_var_diffs['both'])) - out.side_by_side('Total number of non-shared items:', str(num_var_diffs['left']), str(num_var_diffs['right'])) + out.side_by_side( + 'Total number of shared items:', str(num_var_diffs['both']), str(num_var_diffs['both']) + ) + out.side_by_side( + 'Total number of non-shared items:', str(num_var_diffs['left']), str(num_var_diffs['right']) + ) return num_var_diffs['left'], num_var_diffs['right'], num_var_diffs['both'] -def _print_group_details_side_by_side(out, - group_a: Union[netCDF4.Dataset, netCDF4.Group], - group_a_name: str, - group_b: Union[netCDF4.Dataset, netCDF4.Group], - group_b_name: str, - group_counter: int, - num_var_diffs: dict, - show_attributes: bool, - show_chunks: bool) -> None: +def _print_group_details_side_by_side( + out, + group_a: Union[netCDF4.Dataset, netCDF4.Group], + group_a_name: str, + group_b: Union[netCDF4.Dataset, netCDF4.Group], + group_b_name: str, + group_counter: int, + num_var_diffs: dict, + show_attributes: bool, + show_chunks: bool, +) -> None: out.side_by_side(" ", " ", " ", dash_line=False, highlight_diff=False) - out.side_by_side(f"GROUP #{group_counter:02}", group_a_name.strip(), group_b_name.strip(), - dash_line=True, highlight_diff=False) + out.side_by_side( + f"GROUP #{group_counter:02}", + group_a_name.strip(), + group_b_name.strip(), + dash_line=True, + highlight_diff=False, + ) # Count the number of variables in this group as long as this group exists. vars_a_sorted, vars_b_sorted = "", "" @@ -282,7 +327,9 @@ def _print_group_details_side_by_side(out, vars_a_sorted = sorted(group_a.variables) if group_b: vars_b_sorted = sorted(group_b.variables) - out.side_by_side('num variables in group:', len(vars_a_sorted), len(vars_b_sorted), highlight_diff=True) + out.side_by_side( + 'num variables in group:', len(vars_a_sorted), len(vars_b_sorted), highlight_diff=True + ) out.side_by_side('-', '-', '-', dash_line=True) # Count differences between the lists of variables in this group. @@ -294,19 +341,26 @@ def _print_group_details_side_by_side(out, # Go through each variable in the current group. for variable_pair in common_elements(vars_a_sorted, vars_b_sorted): # Get and print the properties of each variable - _print_var_properties_side_by_side(out, - _var_properties(group_a, variable_pair[1]), - _var_properties(group_b, variable_pair[2]), - show_chunks=show_chunks, show_attributes=show_attributes) + _print_var_properties_side_by_side( + out, + _var_properties(group_a, variable_pair[1]), + _var_properties(group_b, variable_pair[2]), + show_chunks=show_chunks, + show_attributes=show_attributes, + ) -def _print_var_properties_side_by_side(out, - v_a: VarProperties, - v_b: VarProperties, - show_chunks: bool = False, - show_attributes: bool = False): +def _print_var_properties_side_by_side( + out, + v_a: VarProperties, + v_b: VarProperties, + show_chunks: bool = False, + show_attributes: bool = False, +): # Variable name - out.side_by_side("-----VARIABLE-----:", v_a.varname[:47], v_b.varname[:47], highlight_diff=False) + out.side_by_side( + "-----VARIABLE-----:", v_a.varname[:47], v_b.varname[:47], highlight_diff=False + ) # Data type out.side_by_side("dtype:", v_a.dtype, v_b.dtype, highlight_diff=True) @@ -330,7 +384,9 @@ def _print_var_properties_side_by_side(out, attr_a = _get_attribute_value_as_str(v_a, attr_a_key) attr_b = _get_attribute_value_as_str(v_b, attr_b_key) # Check whether attr_a_key is empty, because it might be if the variable doesn't exist in File A. - out.side_by_side(f"{attr_a_key if attr_a_key else attr_b_key}:", attr_a, attr_b, highlight_diff=True) + out.side_by_side( + f"{attr_a_key if attr_a_key else attr_b_key}:", attr_a, attr_b, highlight_diff=True + ) # Scale Factor if getattr(v_a.variable, 'scale_factor', None): @@ -344,8 +400,8 @@ def _print_var_properties_side_by_side(out, if (sf_a != " ") or (sf_b != " "): out.side_by_side("sf:", str(sf_a), str(sf_b), highlight_diff=True) -def _var_properties(group: Union[netCDF4.Dataset, netCDF4.Group], - varname: str) -> VarProperties: + +def _var_properties(group: Union[netCDF4.Dataset, netCDF4.Group], varname: str) -> VarProperties: """Get the properties of a variable. Parameters @@ -370,8 +426,7 @@ def _var_properties(group: Union[netCDF4.Dataset, netCDF4.Group], v_dtype = str(the_variable.dtype) v_shape = str(the_variable.shape).strip() v_chunking = str(the_variable.chunking()).strip() - v_attributes = {name: getattr(the_variable, name) - for name in the_variable.ncattrs()} + v_attributes = {name: getattr(the_variable, name) for name in the_variable.ncattrs()} else: the_variable = None v_dtype = "" @@ -381,11 +436,10 @@ def _var_properties(group: Union[netCDF4.Dataset, netCDF4.Group], return VarProperties(varname, the_variable, v_dtype, v_shape, v_chunking, v_attributes) -def _match_random_value(out: Outputter, - nc_var_a: netCDF4.Variable, - nc_var_b: netCDF4.Variable, - thresh: float = 1e-6 - ) -> Union[bool, None]: + +def _match_random_value( + out: Outputter, nc_var_a: netCDF4.Variable, nc_var_b: netCDF4.Variable, thresh: float = 1e-6 +) -> Union[bool, None]: """Check whether a randomly selected data point matches between two variables. Returns @@ -422,12 +476,13 @@ def _match_random_value(out: Outputter, return True + def _print_sample_values(out: Outputter, nc_filepath, groupname: str, varname: str) -> None: comparison_variable = xr.open_dataset(nc_filepath, backend_kwargs={"group": groupname})[varname] out.print(comparison_variable.values[0, :], colors=False) -def _get_attribute_value_as_str(varprops: VarProperties, - attribute_key: str) -> str: + +def _get_attribute_value_as_str(varprops: VarProperties, attribute_key: str) -> str: if attribute_key and (attribute_key in varprops.attributes): attr = varprops.attributes[attribute_key] if isinstance(attr, Iterable) and not isinstance(attr, (str, float)): @@ -441,9 +496,8 @@ def _get_attribute_value_as_str(varprops: VarProperties, return "" -def _get_vars(nc_filepath: Path, - groupname: str, - ) -> list: + +def _get_vars(nc_filepath: Path, groupname: str) -> list: try: grp = xr.open_dataset(nc_filepath, backend_kwargs={"group": groupname}) except OSError as err: @@ -453,15 +507,14 @@ def _get_vars(nc_filepath: Path, return grp_varlist -def _get_groups(nc_filepath: Path, - ) -> list: + +def _get_groups(nc_filepath: Path) -> list: with netCDF4.Dataset(nc_filepath) as dataset: groups_list = list(dataset.groups.keys()) return groups_list -def _get_dims(nc_filepath: Path, - ) -> list: +def _get_dims(nc_filepath: Path) -> list: def __get_dim_list(decode_times=True): with xr.open_dataset(nc_filepath, decode_times=decode_times) as dataset: return list(dataset.dims.items()) diff --git a/ncompare/printing.py b/ncompare/printing.py index e5a6151..3c49411 100644 --- a/ncompare/printing.py +++ b/ncompare/printing.py @@ -14,10 +14,10 @@ from ncompare.sequence_operations import common_elements, count_diffs - # Set up regex remover of ANSI color escape sequences # From -ansi_escape = re.compile(r''' +ansi_escape = re.compile( + r''' \x1B # ESC (?: # 7-bit C1 Fe (except CSI) [@-Z\\-_] @@ -27,17 +27,22 @@ [ -/]* # Intermediate bytes [@-~] # Final byte ) -''', re.VERBOSE) +''', + re.VERBOSE, +) + class Outputter: """Handler for print statements and saving to text and/or csv files.""" _difference_marker = "***" - def __init__(self, - keep_print_history: bool = False, - no_color: bool = False, - text_file: Union[str, Path] = None): + def __init__( + self, + keep_print_history: bool = False, + no_color: bool = False, + text_file: Union[str, Path] = None, + ): """Set up the handling of printing and saving destinations. Parameters @@ -66,7 +71,9 @@ def __init__(self, if filepath.exists(): pass # This will overwrite any existing file at this path, if one exists. - self._text_file_obj = open(filepath, "w", encoding="utf-8") # pylint: disable=consider-using-with + self._text_file_obj = open( + filepath, "w", encoding="utf-8" + ) # pylint: disable=consider-using-with else: self._text_file_obj = None @@ -77,11 +84,9 @@ def __exit__(self, exc_type, exc_value, exc_traceback): # noqa: D105 if self._text_file_obj: self._text_file_obj.close() - def print(self, - string: str = "", - colors: bool = False, - add_to_history: bool = False, - **print_args) -> None: + def print( + self, string: str = "", colors: bool = False, add_to_history: bool = False, **print_args + ) -> None: """Print text using custom options. Parameters @@ -130,8 +135,9 @@ def _parse_single_str(s): # pylint: disable=invalid-name try: string = str(item) except Exception as err: - raise TypeError(f"Error <{err}> with {str(item)}! Expected a string; got a <{type(item)}>.") \ - from err + raise TypeError( + f"Error <{err}> with {str(item)}! Expected a string; got a <{type(item)}>." + ) from err else: string = item @@ -147,8 +153,7 @@ def _make_normal(string): """Return text with normal color and style.""" return Fore.WHITE + Style.RESET_ALL + str(string) - def side_by_side(self, str_a, str_b, str_c, - dash_line=False, highlight_diff=False) -> None: + def side_by_side(self, str_a, str_b, str_c, dash_line=False, highlight_diff=False) -> None: """Print three strings on one line, with customized formatting and an optional marker in the fourth column. Parameters @@ -187,13 +192,20 @@ def side_by_side_list_diff(self, list_a: list, list_b: list, counter_prefix="") counter_prefix """ for idx, item_a, item_b in common_elements(list_a, list_b): - self.side_by_side(f"{counter_prefix} #{idx:02}", item_a.strip(), item_b.strip(), - dash_line=True, highlight_diff=True) - - def lists_diff(self, - list_a: list, list_b: list, - ignore_order: bool = True, - ) -> tuple[int, int, int]: + self.side_by_side( + f"{counter_prefix} #{idx:02}", + item_a.strip(), + item_b.strip(), + dash_line=True, + highlight_diff=True, + ) + + def lists_diff( + self, + list_a: list, + list_b: list, + ignore_order: bool = True, + ) -> tuple[int, int, int]: """Compare two lists and state whether there are differences.""" set_a, set_b = set(list_a), set(list_b) @@ -218,8 +230,11 @@ def lists_diff(self, # If contents are not the same, continue... left, right, both = count_diffs(list_a, list_b) - self.print("\t" + "Are all items the same? ---> " + Fore.RED + f"{str(contents_are_same)}." - f" ({_item_is_or_are(both)} shared, out of {len(s_union)} total.)", add_to_history=True) + self.print( + "\t" + "Are all items the same? ---> " + Fore.RED + f"{str(contents_are_same)}." + f" ({_item_is_or_are(both)} shared, out of {len(s_union)} total.)", + add_to_history=True, + ) # Which variables are different? self.print("\t" + Fore.RED + "Which items are different?") @@ -264,12 +279,14 @@ def write_history_to_excel(self, filename: Union[str, Path] = "test.xlsx"): # Wrap up workbook.save(filename) + def _item_is_or_are(count): if count == 1: return f"{count} item is" return f"{count} items are" + def _excel_red_cells(data, sheet): """Stylize cells in Excel with a red font.""" for cell in data: @@ -277,6 +294,7 @@ def _excel_red_cells(data, sheet): cell.font = Font(bold=True, color="FFFF0000") yield cell + def _excel_bold_underline_cells(data, sheet): """Stylize cells in Excel with a bold and underlined font.""" for cell in data: diff --git a/ncompare/sequence_operations.py b/ncompare/sequence_operations.py index 47084e8..8b6cc79 100644 --- a/ncompare/sequence_operations.py +++ b/ncompare/sequence_operations.py @@ -5,9 +5,7 @@ from ncompare.utils import coerce_to_str -def common_elements(sequence_a: Iterable, - sequence_b: Iterable - ) -> tuple[int, str, str]: +def common_elements(sequence_a: Iterable, sequence_b: Iterable) -> tuple[int, str, str]: """Loop over combined items of two iterables, and yield aligned item pairs. Note @@ -33,7 +31,8 @@ def common_elements(sequence_a: Iterable, if (item not in a_sorted) and (item not in b_sorted): raise ValueError( "Unexpected condition where an item was not found " - "but all items should exist in at least one list.") + "but all items should exist in at least one list." + ) if item not in a_sorted: item_a = '' @@ -43,9 +42,9 @@ def common_elements(sequence_a: Iterable, yield i, item_a, item_b -def count_diffs(list_a: list[Union[str, int]], - list_b: list[Union[str, int]] - ) -> tuple[int, int, int]: +def count_diffs( + list_a: list[Union[str, int]], list_b: list[Union[str, int]] +) -> tuple[int, int, int]: """Count how many elements are either uniquely in one list or the other, or in both. Note diff --git a/ncompare/utils.py b/ncompare/utils.py index ad6e16b..75b7b15 100644 --- a/ncompare/utils.py +++ b/ncompare/utils.py @@ -22,8 +22,8 @@ def ensure_valid_path_exists(should_be_path: Union[str, Path]) -> Path: raise TypeError(wrong_type_msg + str(type(should_be_path))) -def ensure_valid_path_with_suffix(should_be_path: Union[str, Path], - suffix: str = None) -> Path: + +def ensure_valid_path_with_suffix(should_be_path: Union[str, Path], suffix: str = None) -> Path: """Coerce input to a pathlib.Path with given suffix.""" wrong_type_msg = "Unexpected type for something that should be convertable to a Path: " @@ -36,6 +36,7 @@ def ensure_valid_path_with_suffix(should_be_path: Union[str, Path], return path_obj.with_suffix(suffix) + def coerce_to_str(some_object: Union[str, int, tuple]): """Ensure the type is a string.""" if isinstance(some_object, str):