Home | History | Annotate | Download | only in common
      1 #
      2 # Copyright (C) 2016 The Android Open Source Project
      3 #
      4 # Licensed under the Apache License, Version 2.0 (the "License");
      5 # you may not use this file except in compliance with the License.
      6 # You may obtain a copy of the License at
      7 #
      8 #      http://www.apache.org/licenses/LICENSE-2.0
      9 #
     10 # Unless required by applicable law or agreed to in writing, software
     11 # distributed under the License is distributed on an "AS IS" BASIS,
     12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 # See the License for the specific language governing permissions and
     14 # limitations under the License.
     15 #
     16 
     17 import itertools
     18 import os
     19 
     20 DEFAULT_COMMENT_CHAR = '#'
     21 
     22 
     23 def ItemsToStr(input_list):
     24     '''Convert item in a list to string.
     25 
     26     Args:
     27         input_list: list of objects, the list to convert
     28 
     29     Return:
     30         A list of string where objects were converted to string using str function.
     31         None if input list is None.
     32     '''
     33     if not input_list:
     34         return input_list
     35     return list(map(str, input_list))
     36 
     37 
     38 def ExpandItemDelimiters(input_list,
     39                          delimiter,
     40                          strip=False,
     41                          to_str=False,
     42                          remove_empty=True):
     43     '''Expand list items that contain the given delimiter.
     44 
     45     Args:
     46         input_list: list of string, a list whose item may contain a delimiter
     47         delimiter: string
     48         strip: bool, whether to strip items after expanding. Default is False
     49         to_str: bool, whether to convert output items in string.
     50                 Default is False
     51         remove_empty: bool, whether to remove empty string in result list.
     52                       Will not remove None items. Default: True
     53 
     54     Returns:
     55         The expended list, which may be the same with input list
     56         if no delimiter found; None if input list is None
     57     '''
     58     if input_list is None:
     59         return None
     60 
     61     do_strip = lambda s: s.strip() if strip else s
     62     do_str = lambda s: str(s) if to_str else s
     63 
     64     expended_list_generator = (item.split(delimiter) for item in input_list)
     65     result = [
     66         do_strip(do_str(s))
     67         for s in itertools.chain.from_iterable(expended_list_generator)
     68     ]
     69     return filter(lambda s: str(s) != '', result) if remove_empty else result
     70 
     71 
     72 def DeduplicateKeepOrder(input):
     73     '''Remove duplicate items from a sequence while keeping the item order.
     74 
     75     Args:
     76         input: a sequence that might have duplicated items.
     77 
     78     Returns:
     79         A deduplicated list where item order is kept.
     80     '''
     81     return MergeUniqueKeepOrder(input)
     82 
     83 
     84 def MergeUniqueKeepOrder(*lists):
     85     '''Merge two list, remove duplicate items, and order.
     86 
     87     Args:
     88         lists: any number of lists
     89 
     90     Returns:
     91         A merged list where items are unique and original order is kept.
     92     '''
     93     seen = set()
     94     return [
     95         x for x in itertools.chain(*lists) if not (x in seen or seen.add(x))
     96     ]
     97 
     98 
     99 def LoadListFromCommentedTextFile(file_path,
    100                                   to_str=True,
    101                                   to_strip=True,
    102                                   exclude_empty_line=True,
    103                                   exclude_comment_line=True,
    104                                   exclude_trailing_comment=True,
    105                                   remove_duplicates=False,
    106                                   remove_line_breaks=True,
    107                                   comment_char=DEFAULT_COMMENT_CHAR):
    108     '''Read commented text file into a list of lines.
    109 
    110         Comments or empty lines will be excluded by default.
    111 
    112         Args:
    113             file_path: string, path to file
    114             to_str: bool, whether to convert lines to string in result list.
    115                     Default value is True.
    116             to_strip: bool, whether to strip lines in result list.
    117                       Default value is True.
    118             exclude_empty_line: bool, whether to exclude empty items in result list
    119                                 Default value is True.
    120             exclude_comment_line: bool, whether to exclude lines that only contains comments.
    121                                   If a line starts with spaces and ends with comments it
    122                                   will still be excluded even if to_trim is False.
    123                                   Default value is True.
    124             exclude_trailing_comment: bool, whether to remove trailing comments
    125                                       from result items.
    126                                       Default value is True.
    127             remove_duplicates: bool, whether to remove duplicate items in output list.
    128                                Default value is False.
    129             remove_line_breaks: bool, whether to remove trailing trailing
    130                                 new line characters from result items.
    131                                 Default value is True.
    132             comment_char: string, character to denote comment.
    133                           Default value is pound (#).
    134 
    135         Returns:
    136             a list of string. None if file does not exist.
    137         '''
    138     if not os.path.isfile(file_path):
    139         logging.error('The path provided is not a file or does not exist: %s',
    140                       file_path)
    141         return None
    142 
    143     with open(file_path, 'r') as f:
    144         return LoadListFromCommentedText(
    145             f.read(),
    146             to_str,
    147             to_strip,
    148             exclude_empty_line,
    149             exclude_comment_line,
    150             exclude_trailing_comment,
    151             remove_duplicates,
    152             remove_line_breaks,
    153             comment_char=DEFAULT_COMMENT_CHAR)
    154 
    155 
    156 def LoadListFromCommentedText(text,
    157                               to_str=True,
    158                               to_strip=True,
    159                               exclude_empty_line=True,
    160                               exclude_comment_line=True,
    161                               exclude_trailing_comment=True,
    162                               remove_duplicates=False,
    163                               remove_line_breaks=True,
    164                               comment_char=DEFAULT_COMMENT_CHAR):
    165     '''Read commented text into a list of lines.
    166 
    167         Comments or empty lines will be excluded by default.
    168 
    169         Args:
    170             text: string, text to parse
    171             to_str: bool, whether to convert lines to string in result list.
    172                     Default value is True.
    173             to_strip: bool, whether to strip lines in result list.
    174                       Default value is True.
    175             exclude_empty_line: bool, whether to exclude empty items in result list
    176                                 Default value is True.
    177             exclude_comment_line: bool, whether to exclude lines that only contains comments.
    178                                   If a line starts with spaces and ends with comments it
    179                                   will still be excluded even if to_trim is False.
    180                                   Default value is True.
    181             exclude_trailing_comment: bool, whether to remove trailing comments
    182                                       from result items.
    183                                       Default value is True.
    184             remove_duplicates: bool, whether to remove duplicate items in output list.
    185                                Default value is False.
    186             remove_line_breaks: bool, whether to remove trailing trailing
    187                                 new line characters from result items.
    188                                 Default value is True.
    189             comment_char: string, character to denote comment.
    190                           Default value is pound (#).
    191 
    192         Returns:
    193             a list of string.
    194         '''
    195     lines = text.splitlines(not remove_line_breaks)
    196 
    197     if to_str:
    198         lines = map(str, lines)
    199 
    200     if exclude_trailing_comment:
    201 
    202         def RemoveComment(line):
    203             idx = line.find(comment_char)
    204             if idx < 0:
    205                 return line
    206             else:
    207                 return line[:idx]
    208 
    209         lines = map(RemoveComment, lines)
    210 
    211     if to_strip:
    212         lines = map(lambda line: line.strip(), lines)
    213 
    214     if exclude_comment_line:
    215         lines = filter(lambda line: not line.strip().startswith(comment_char),
    216                        lines)
    217 
    218     if exclude_empty_line:
    219         lines = filter(bool, lines)
    220 
    221     if remove_duplicates:
    222         lines = DeduplicateKeepOrder(lines)
    223 
    224     return lines
    225