# Copyright (C) 2020 Red Hat Inc. # # Authors: # Eduardo Habkost # # This work is licensed under the terms of the GNU GPL, version 2. See # the COPYING file in the top-level directory. from typing import * import logging logger = logging.getLogger(__name__) DBG = logger.debug INFO = logger.info WARN = logger.warning T = TypeVar('T') def opt_compare(a: T, b: T) -> bool: """Compare two values, ignoring mismatches if one of them is None""" return (a is None) or (b is None) or (a == b) def merge(a: T, b: T) -> T: """Merge two values if they matched using opt_compare()""" assert opt_compare(a, b) if a is None: return b else: return a def test_comp_merge(): assert opt_compare(None, 1) == True assert opt_compare(2, None) == True assert opt_compare(1, 1) == True assert opt_compare(1, 2) == False assert merge(None, None) is None assert merge(None, 10) == 10 assert merge(10, None) == 10 assert merge(10, 10) == 10 LineNumber = NewType('LineNumber', int) ColumnNumber = NewType('ColumnNumber', int) class LineAndColumn(NamedTuple): line: int col: int def __str__(self): return '%d:%d' % (self.line, self.col) def line_col(s, position: int) -> LineAndColumn: """Return line and column for a char position in string Character position starts in 0, but lines and columns start in 1. """ before = s[:position] lines = before.split('\n') line = len(lines) col = len(lines[-1]) + 1 return LineAndColumn(line, col) def test_line_col(): assert line_col('abc\ndefg\nhijkl', 0) == (1, 1) assert line_col('abc\ndefg\nhijkl', 2) == (1, 3) assert line_col('abc\ndefg\nhijkl', 3) == (1, 4) assert line_col('abc\ndefg\nhijkl', 4) == (2, 1) assert line_col('abc\ndefg\nhijkl', 10) == (3, 2) def not_optional(arg: Optional[T]) -> T: assert arg is not None return arg __all__ = ['not_optional', 'opt_compare', 'merge', 'line_col', 'LineAndColumn']