Source code for psi4.driver.p4util.text

#
# @BEGIN LICENSE
#
# Psi4: an open-source quantum chemistry software package
#
# Copyright (c) 2007-2024 The Psi4 Developers.
#
# The copyrights for code used from other parties are included in
# the corresponding files.
#
# This file is part of Psi4.
#
# Psi4 is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, version 3.
#
# Psi4 is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with Psi4; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# @END LICENSE
#
"""Module with utility classes and functions related
to data tables and text.

"""

__all__ = [
    "banner",
    "find_approximate_string_matches",
    "levenshtein",
    "message_box",
]

from typing import List, Optional

from psi4 import core

from .. import constants






[docs] def levenshtein(seq1: str, seq2:str) -> int: """Compute the Levenshtein distance between two strings. Parameters ---------- seq1 First string. seq2 Second string. """ oneago = None thisrow = list(range(1, len(seq2) + 1)) + [0] for x in range(len(seq1)): twoago, oneago, thisrow = oneago, thisrow, [0] * len(seq2) + [x + 1] for y in range(len(seq2)): delcost = oneago[y] + 1 addcost = thisrow[y - 1] + 1 subcost = oneago[y - 1] + (seq1[x] != seq2[y]) thisrow[y] = min(delcost, addcost, subcost) return thisrow[len(seq2) - 1]
[docs] def find_approximate_string_matches(seq1: str, options: List[str], max_distance: int) -> List[str]: """Find list of approximate (within `max_distance`) matches to string `seq1` among `options`. Parameters ---------- seq1 Target string to look for near matches to. options Alternatives among which to look for near matches to `seq1`. max_distance Maximum Levenshtein distance from `seq1` to return. """ return [seq2 for seq2 in options if (levenshtein(seq1, seq2) <= max_distance)]
[docs] def message_box(message: str, max_width: int = 80, min_width: int = 30) -> str: """Put a message string into a box for extra attention. Parameters ---------- message Message string to be boxed. max_width Maximal character width of the box. min_width Minimal character width of the box. Returns ------- str Box containing the message as a multiline string. """ from textwrap import wrap # ensure box is within min/max boundaries msg = message.splitlines() max_line = len(max(msg, key=len)) box_width = max(min(max_width, max_line), min_width) error_str = [] error_str.append('\n!' + '-' * box_width + '--!\n') error_str.append('!' + ' ' * box_width + ' !\n') fmt = "! {:" + str(box_width) + "} !\n" for line in msg[:]: error_str.extend([fmt.format(x) for x in wrap(line, box_width, subsequent_indent=" ")]) error_str.append('!' + ' ' * box_width + ' !\n') error_str.append('!' + '-' * box_width + '--!\n') error_str = ''.join(error_str) return error_str