Robot Framework Integrated Development Environment (RIDE)
robotreader.py
Go to the documentation of this file.
1 # Copyright 2008-2015 Nokia Networks
2 # Copyright 2016- Robot Framework Foundation
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 import re
17 
18 from robotide.lib.robot.output import LOGGER
19 from robotide.lib.robot.utils import Utf8Reader, prepr
20 
21 NBSP = u'\xa0'
22 
23 
24 class RobotReader():
25 
26  def __init__(self, spaces=2):
27  self._spaces_spaces = spaces
28  # self._space_splitter = re.compile(r"[ \t\xa0]{"+f"{self._spaces}"+"}|\t+") # Only change when is cell_section
29  self._space_splitter_space_splitter = re.compile(r"[ \t\xa0]{2}|\t+")
30  self._pipe_splitter_pipe_splitter = re.compile(u'[ \t\xa0]+\|(?=[ \t\xa0]+)')
31  self._pipe_starts_pipe_starts = ('|', '| ', '|\t', u'|\xa0')
32  self._pipe_ends_pipe_ends = (' |', '\t|', u'\xa0|')
33  self._separator_check_separator_check = False
34  self._cell_section_cell_section = False
35  # print(f"DEBUG: RFLib RobotReader init spaces={self._spaces}")
36 
37  def read(self, file, populator, path=None):
38  path = path or getattr(file, 'name', '<file-like object>')
39  process = table_start = preamble = False
40  # print(f"DEBUG: RFLib RobotReader start Reading file")
41  for lineno, line in enumerate(Utf8Reader(file).readlines(), start=1):
42  if not self._separator_check_separator_check:
43  self.check_separatorcheck_separator(line.rstrip())
44  cells = self.split_rowsplit_row(line.rstrip())
45 
47  if line.lstrip().startswith('#'):
48  if cells[0] == '': # There is an initial empty cell, when #
49  cells.pop(0)
50  # populator.add(cells)
51  # continue
52  if cells and cells[0].strip().startswith('*') and \
53  populator.start_table([c.replace('*', '').strip()
54  for c in cells]):
55  process = table_start = True
56  preamble = False
57  elif not table_start:
58  # print(f"DEBUG: RFLib RobotReader Enter Preamble block, lineno={lineno} cells={cells}")
59  if not preamble:
60  preamble = True
61  populator.add_preamble(line)
62  elif process and not preamble:
63  # print(f"DEBUG: robotreader.read original line={line}\nparser={cells}")
64  populator.add(cells)
65  return populator.eof()
66 
67  def sharp_strip(self, line):
68  row = []
69  i = 0
70  start_d_quote = end_d_quote = False
71  start_s_quote = end_s_quote = False
72  index = len(line)
73  while i < len(line):
74  if line[i] == '"':
75  if end_d_quote:
76  start_d_quote = True
77  end_d_quote = False
78  elif start_d_quote:
79  end_d_quote = True
80  else:
81  start_d_quote = True
82  if line[i] == "'":
83  if end_s_quote:
84  start_s_quote = True
85  end_s_quote = False
86  elif start_s_quote:
87  end_s_quote = True
88  else:
89  start_s_quote = True
90  if line[i] == '#' and not start_d_quote and not start_s_quote:
91  if i == 0:
92  index = 0
93  break
94  try:
95  if i>0 and line[i-1] != '\\' and (line[i+1] == ' ' or line[i+1] == '#'):
96  index = i
97  # print(f"DEBUG: RFLib RobotReader sharp_strip BREAK at # index={index}")
98  break
99  except IndexError:
100  i += 1
101  continue
102  i += 1
103  if index < len(line):
104  cells = self._space_splitter_space_splitter.split(line[:index])
105  row.extend(cells)
106  row.append(line[index:])
107  else:
108  row = self._space_splitter_space_splitter.split(line)
109  # print(f"DEBUG: RFLib RobotReader sharp_strip after cells split index={index} row={row[:]}")
110  # Remove empty cells after first non-empty
111  first_non_empty = -1
112  if row:
113  for i, v in enumerate(row):
114  if v != '':
115  first_non_empty = i
116  break
117  # print(f"DEBUG: RFLib RobotReader sharp_strip row first_non_empty={first_non_empty}")
118  if first_non_empty != -1:
119  for i in range(len(row)-1, first_non_empty, -1):
120  if row[i] == '':
121  # print(f"DEBUG: RFLib RobotReader sharp_strip popping ow i ={i} row[i]={row[i]}")
122  row.pop(i)
123  # Remove initial empty cell
124  if len(row) > 1 and first_non_empty > 1 and row[0] == '' and row[1] != '': # don't cancel indentation
125  # print(f"DEBUG: RFLib RobotReader sharp_strip removing initial empty cell first_non_empty={first_non_empty}")
126  row.pop(0)
127  # print(f"DEBUG: RFLib RobotReader sharp_strip returning row={row[:]}")
128  return row
129 
130  def split_row(self, row):
131  if row[:2] in self._pipe_starts_pipe_starts:
132  row = row[1:-1] if row[-2:] in self._pipe_ends_pipe_ends else row[1:]
133  return [self._strip_whitespace_strip_whitespace(cell)
134  for cell in self._pipe_splitter_pipe_splitter.split(row)]
135  return self.sharp_stripsharp_strip(row)
136 
137  def _check_deprecations(self, cells, path, line_number):
138  for original in cells:
139  normalized = self._normalize_whitespace_normalize_whitespace(original)
140  if normalized != original:
141  if len(normalized) != len(original):
142  msg = 'Collapsing consecutive whitespace'
143  else:
144  msg = 'Converting whitespace characters to ASCII spaces'
145  LOGGER.warn("%s during parsing is deprecated. Fix %s in file "
146  "'%s' on line %d."
147  % (msg, prepr(original), path, line_number))
148  yield normalized
149 
150  @classmethod
151  def _strip_whitespace(cls, string):
152  return string.strip()
153 
154  @staticmethod
156  if string.startswith('#'):
157  return string
158  return ' '.join(string.split())
159 
160 
167  def check_separator(self, line):
168  if not line.startswith('*') and not line.startswith('#'):
169  if not self._separator_check_separator_check and line[:2] in self._pipe_starts_pipe_starts:
170  self._separator_check_separator_check = True
171  # print(f"DEBUG: RFLib RobotReader check_separator PIPE separator")
172  return
173  idx = 0
174  for idx in range(0, len(line)):
175  if line[idx] != ' ':
176  break
177  if 2 <= idx <= 10: # This max limit is reasonable
178  self._spaces_spaces = idx
179  self._space_splitter_space_splitter = re.compile(r"[ \t\xa0]{" + f"{self._spaces}" + "}|\t+")
180  self._separator_check_separator_check = True
181  # print(f"DEBUG: RFLib RobotReader check_separator changed spaces={self._spaces}")
182  return
def read(self, file, populator, path=None)
Definition: robotreader.py:37
def _check_deprecations(self, cells, path, line_number)
Definition: robotreader.py:137
def check_separator(self, line)
if line.startswith('*') and not self._cell_section: row = line.strip('*').strip(' ') if row in ['Keyw...
Definition: robotreader.py:167
def prepr(item, width=80)
Definition: unic.py:69