Skip to content

Commit

Permalink
opencsp/common/lib/tool: test docs
Browse files Browse the repository at this point in the history
  • Loading branch information
e10harvey committed Nov 12, 2024
1 parent 97ed05d commit 42b73de
Show file tree
Hide file tree
Showing 9 changed files with 758 additions and 36 deletions.
258 changes: 238 additions & 20 deletions opencsp/common/lib/tool/dict_tools.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,67 @@
"""
Utilities for dictionaries.
"""

import opencsp.common.lib.tool.file_tools as ft


# ACCESS


def number_of_keys(input_dict):
"""
Return the number of keys in the given dictionary.
Parameters
----------
input_dict : dict
The dictionary for which to count the keys.
Returns
-------
int
The number of keys in the input dictionary.
"""
# "ChatGPT 4o" assisted with generating this docstring.
return len(input_dict.keys())


def sorted_keys(input_dict):
"""
Return the dictionary keys, in a sorted list.
Because this constructs a list and sorts it, this is slower than using keys(), but provides the keys in a predictable order.
Return the keys of the dictionary in a sorted list.
Parameters
----------
input_dict : dict
The dictionary whose keys are to be sorted.
Returns
-------
list
A sorted list of the keys in the input dictionary.
Notes
-----
This function constructs a list of keys and sorts it, which may be slower than using `keys()`,
but provides the keys in a predictable order.
"""
# "ChatGPT 4o" assisted with generating this docstring.
key_list = list(input_dict.keys())
key_list.sort()
return key_list


def list_of_values_in_sorted_key_order(input_dict):
"""
Return a list of values from the dictionary in the order of sorted keys.
Parameters
----------
input_dict : dict
The dictionary from which to extract values.
Returns
-------
list
A list of values corresponding to the sorted keys of the input dictionary.
"""
# "ChatGPT 4o" assisted with generating this docstring.
output_list = []
for key in sorted_keys(input_dict):
output_list.append(input_dict[key])
Expand All @@ -42,8 +78,24 @@ def print_dict(
indent=None,
): # Number of blanks to print at the beginning of each line.
"""
Prints a simple dictionary, limiting print-out length both laterally and vertically.
Print a simple dictionary, limiting the output length both laterally and vertically.
Parameters
----------
input_dict : dict
The dictionary to print.
max_keys : int, optional
The maximum number of keys to print. An ellipsis will be shown if there are more keys.
max_value_length : int, optional
The maximum length of values to print. An ellipsis will be shown if values exceed this length.
indent : int, optional
The number of spaces to print at the beginning of each line for indentation.
Returns
-------
None
"""
# "ChatGPT 4o" assisted with generating this docstring.
# Sort key list for consistent output order.
key_list = sorted_keys(input_dict)
# Content.
Expand Down Expand Up @@ -75,8 +127,28 @@ def print_dict_of_dicts(
indent_2=4,
): # Number of additional blanks to print for each second-level line.
"""
Prints a one-level nested dictionary, limiting print-out length both laterally and vertically.
Print a one-level nested dictionary, limiting the output length both laterally and vertically.
Parameters
----------
input_dict : dict
The dictionary to print, where values are themselves dictionaries.
max_keys_1 : int, optional
The maximum number of top-level keys to print. An ellipsis will be shown if there are more keys.
max_keys_2 : int, optional
The maximum number of second-level keys to print. An ellipsis will be shown if there are more keys.
max_value_2_length : int, optional
The maximum length of second-level values to print. An ellipsis will be shown if values exceed this length.
indent_1 : int, optional
The number of spaces to print at the beginning of each top-level line for indentation.
indent_2 : int, optional
The number of additional spaces to print for each second-level line.
Returns
-------
None
"""
# "ChatGPT 4o" assisted with generating this docstring.
# Indentation.
indent_level_1 = indent_1
indent_level_2 = indent_1 + indent_2
Expand Down Expand Up @@ -121,8 +193,32 @@ def print_dict_of_dict_of_dicts(
indent_3=4,
): # Number of additional blanks to print for each third-level line.
"""
Prints a one-level nested dictionary, limiting print-out length both laterally and vertically.
Print a two-level nested dictionary, limiting the output length both laterally and vertically.
Parameters
----------
input_dict : dict
The dictionary to print, where values are dictionaries that themselves contain dictionaries.
max_keys_1 : int, optional
The maximum number of top-level keys to print. An ellipsis will be shown if there are more keys.
max_keys_2 : int, optional
The maximum number of second-level keys to print. An ellipsis will be shown if there are more keys.
max_keys_3 : int, optional
The maximum number of third-level keys to print. An ellipsis will be shown if there are more keys.
max_value_3_length : int, optional
The maximum length of third-level values to print. An ellipsis will be shown if values exceed this length.
indent_1 : int, optional
The number of spaces to print at the beginning of each top-level line for indentation.
indent_2 : int, optional
The number of additional spaces to print for each second-level line.
indent_3 : int, optional
The number of additional spaces to print for each third-level line.
Returns
-------
None
"""
# "ChatGPT 4o" assisted with generating this docstring.
# Indentation.
indent_level_1 = indent_1
indent_level_2 = indent_1 + indent_2
Expand Down Expand Up @@ -181,10 +277,29 @@ def save_list_of_one_level_dicts(
list_of_one_level_dicts, output_dir, output_body, explain, error_if_dir_not_exist, first_key=None
):
"""
A "one_level_dict" is a dictionary with entries that can be converted to strings and written as single entries in a csv file.
Given a list of one_level_dicts, this routine writes the data to a csv file, one dict per line.
Save a list of one-level dictionaries to a CSV file, one dictionary per line.
Parameters
----------
list_of_one_level_dicts : list of dict
A list of dictionaries to save to the CSV file.
output_dir : str
The directory where the CSV file will be saved.
output_body : str
The body of the output filename (without extension).
explain : str
An explanatory string to include in notification output.
error_if_dir_not_exist : bool
If True, raise an error if the output directory does not exist; if False, create the directory if necessary.
first_key : str, optional
A key to prioritize in the CSV heading line.
Returns
-------
str
The full path to the saved CSV file.
"""
# "ChatGPT 4o" assisted with generating this docstring.
if len(list_of_one_level_dicts) == 0:
explain += ' (EMPTY)'
key_list, heading_line = one_level_dict_csv_heading_line(list_of_one_level_dicts, first_key)
Expand All @@ -204,6 +319,22 @@ def save_list_of_one_level_dicts(


def one_level_dict_csv_heading_line(list_of_one_level_dicts, first_key):
"""
Generate the heading line for a CSV file from a list of one-level dictionaries.
Parameters
----------
list_of_one_level_dicts : list of dict
A list of one-level dictionaries to extract headings from.
first_key : str, optional
A key to prioritize in the heading line.
Returns
-------
tuple
A tuple containing the list of keys and the heading line as a string.
"""
# "ChatGPT 4o" assisted with generating this docstring.
# Catch empty input case.
if len(list_of_one_level_dicts) == 0:
return 'No data.'
Expand All @@ -214,6 +345,22 @@ def one_level_dict_csv_heading_line(list_of_one_level_dicts, first_key):


def one_level_dict_csv_heading_line_aux(first_one_level_dict, first_key):
"""
Auxiliary function to generate the heading line for a CSV file from a one-level dictionary.
Parameters
----------
first_one_level_dict : dict
The first one-level dictionary to extract headings from.
first_key : str, optional
A key to prioritize in the heading line.
Returns
-------
tuple
A tuple containing the list of keys and the heading line as a string.
"""
# "ChatGPT 4o" assisted with generating this docstring.
key_list = []
first_key_found = False
for key in first_one_level_dict.keys():
Expand All @@ -240,6 +387,22 @@ def one_level_dict_csv_heading_line_aux(first_one_level_dict, first_key):


def one_level_dict_csv_data_line(key_list, one_level_dict):
"""
Generate a CSV data line from a one-level dictionary.
Parameters
----------
key_list : list
A list of keys to extract values from the dictionary.
one_level_dict : dict
The one-level dictionary to convert to a CSV data line.
Returns
-------
str
A string representing the CSV data line.
"""
# "ChatGPT 4o" assisted with generating this docstring.
# Assemble list of deta entry strings.
data_str_list = []
for key in key_list:
Expand All @@ -262,12 +425,31 @@ def save_list_of_one_level_dict_pairs(
first_key_2=None,
):
"""
A "one_level_dict_pair" is a list [one_level_dict_1, one_level_dict_2] of one_level_dicts.
See above for definition of a one_level_dict.
The keys of the two dicts do not need to be the same.
Given a list of one_level_dicts, this routine writes the data to a csv file, one dict per line.
Save a list of one-level dictionary pairs to a CSV file, one dict per line.
Parameters
----------
list_of_one_level_dict_pairs : list of list
A list of pairs of one-level dictionaries to save to the CSV file.
output_dir : str
The directory where the CSV file will be saved.
output_body : str
The body of the output filename (without extension).
explain : str
An explanatory string to include in notification output.
error_if_dir_not_exist : bool
If True, raise an error if the output directory does not exist; if False, create the directory if necessary.
first_key_1 : str, optional
A key to prioritize in the heading line for the first dictionary.
first_key_2 : str, optional
A key to prioritize in the heading line for the second dictionary.
Returns
-------
str
The full path to the saved CSV file.
"""
# "ChatGPT 4o" assisted with generating this docstring.
if len(list_of_one_level_dict_pairs) == 0:
explain += ' (EMPTY)'
key_list_1, key_list_2, heading_line = one_level_dict_pair_csv_heading_line(
Expand All @@ -290,10 +472,28 @@ def save_list_of_one_level_dict_pairs(

def one_level_dict_pair_csv_heading_line(list_of_one_level_dict_pairs, first_key_1, first_key_2):
"""
Generate the heading line for a CSV file from a list of one-level dictionary pairs.
This routine extracts the headings from each of the two dicts, adding suffixes "_1" or "_2" to the first and
second dictionary keys, respectively. These suffixes are added regardless of whether the dictionaries have
the same or different keys.
Parameters
----------
list_of_one_level_dict_pairs : list of list
A list of pairs of one-level dictionaries to extract headings from.
first_key_1 : str, optional
A key to prioritize in the heading line for the first dictionary.
first_key_2 : str, optional
A key to prioritize in the heading line for the second dictionary.
Returns
-------
tuple
A tuple containing the list of keys for the first dictionary, the list of keys for the second dictionary,
and the combined heading line as a string.
"""
# "ChatGPT 4o" assisted with generating this docstring.
# Catch empty input case.
if len(list_of_one_level_dict_pairs) == 0:
return 'No data.'
Expand All @@ -318,6 +518,24 @@ def one_level_dict_pair_csv_heading_line(list_of_one_level_dict_pairs, first_key


def one_level_dict_pair_csv_data_line(key_list_1, key_list_2, one_level_dict_pair):
"""
Generate a CSV data line from a pair of one-level dictionaries.
Parameters
----------
key_list_1 : list
A list of keys to extract values from the first dictionary.
key_list_2 : list
A list of keys to extract values from the second dictionary.
one_level_dict_pair : list
A pair of one-level dictionaries to convert to a CSV data line.
Returns
-------
str
A string representing the CSV data line for the pair of dictionaries.
"""
# "ChatGPT 4o" assisted with generating this docstring.
# First dictionary data line.
one_level_dict_1 = one_level_dict_pair[0]
data_line_1 = one_level_dict_csv_data_line(key_list_1, one_level_dict_1)
Expand Down
31 changes: 31 additions & 0 deletions opencsp/common/lib/tool/file_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,37 @@ def merge_files(in_files: list[str], out_file: str, overwrite=False, remove_in_f


def convert_shortcuts_to_symlinks(dirname: str):
"""
Convert Windows shortcut files (.lnk) in a specified directory to symbolic links.
This function scans the given directory for shortcut files and replaces them with
symbolic links pointing to the original target files or directories. It handles
nested shortcuts by recursively resolving the target paths.
Parameters
----------
dirname : str
The path to the directory containing the shortcut files to be converted.
Raises
------
FileExistsError
If a symbolic link with the same name already exists as a file or directory.
Exception
If there is an error reading a shortcut or creating a symbolic link.
Notes
-----
This function is designed to work on Windows systems only. It uses the
`win32com.client` module to interact with Windows shortcuts. If the function
is executed on a non-Windows system, it will log a debug message and exit without
performing any actions.
Examples
--------
>>> convert_shortcuts_to_symlinks("C:\\path\\to\\shortcuts")
"""
# "ChatGPT 4o" assisted with generating this docstring.
if os.name == "nt":
# update dirname to use windows "\" seperators
dirname = os.path.normpath(dirname)
Expand Down
Loading

0 comments on commit 42b73de

Please sign in to comment.