Robot Framework Integrated Development Environment (RIDE)
escaping.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 .platform import PY3
19 from .robottypes import is_string
20 
21 
22 if PY3:
23  unichr = chr
24 
25 
28 _CONTROL_WORDS = frozenset(('ELSE', 'ELSE IF', 'AND', 'WITH NAME'))
29 
32 _SEQUENCES_TO_BE_ESCAPED = ('\\', '${', '@{', '%{', '&{', '*{', '=')
33 
34 
35 def escape(item):
36  if not is_string(item):
37  return item
38  if item in _CONTROL_WORDS:
39  return '\\' + item
40  for seq in _SEQUENCES_TO_BE_ESCAPED:
41  if seq in item:
42  item = item.replace(seq, '\\' + seq)
43  return item
44 
45 
46 def unescape(item):
47  if not (is_string(item) and '\\' in item):
48  return item
49  return Unescaper().unescape(item)
50 
51 
52 class Unescaper():
53 
54  def unescape(self, string):
55  return ''.join(self._yield_unescaped_yield_unescaped(string))
56 
57  def _yield_unescaped(self, string):
58  while '\\' in string:
59  finder = EscapeFinder(string)
60  yield finder.before + finder.backslashes
61  if finder.escaped and finder.text:
62  yield self._unescape_unescape(finder.text)
63  else:
64  yield finder.text
65  string = finder.after
66  yield string
67 
68  def _unescape(self, text):
69  try:
70  escape = str(text[0])
71  except UnicodeError:
72  return text
73  try:
74  unescaper = getattr(self, '_unescaper_for_' + escape)
75  except AttributeError:
76  return text
77  else:
78  return unescaper(text[1:])
79 
80  def _unescaper_for_n(self, text):
81  # TODO: Deprecate ignoring space after newline in RF 3.2.
82  if text.startswith(' '):
83  text = text[1:]
84  return '\n' + text
85 
86  def _unescaper_for_r(self, text):
87  return '\r' + text
88 
89  def _unescaper_for_t(self, text):
90  return '\t' + text
91 
92  def _unescaper_for_x(self, text):
93  return self._unescape_character_unescape_character(text, 2, 'x')
94 
95  def _unescaper_for_u(self, text):
96  return self._unescape_character_unescape_character(text, 4, 'u')
97 
98  def _unescaper_for_U(self, text):
99  return self._unescape_character_unescape_character(text, 8, 'U')
100 
101  def _unescape_character(self, text, length, escape):
102  try:
103  char = self._get_character_get_character(text[:length], length)
104  except ValueError:
105  return escape + text
106  else:
107  return char + text[length:]
108 
109  def _get_character(self, text, length):
110  if len(text) < length or not text.isalnum():
111  raise ValueError
112  ordinal = int(text, 16)
113  # No Unicode code points above 0x10FFFF
114  if ordinal > 0x10FFFF:
115  raise ValueError
116  # unichr only supports ordinals up to 0xFFFF with narrow Python builds
117  if ordinal > 0xFFFF:
118  return eval("u'\\U%08x'" % ordinal)
119  return unichr(ordinal)
120 
121 
122 class EscapeFinder():
123 
126  _escaped = re.compile(r'(\\+)([^\\]*)')
127 
128  def __init__(self, string):
129  res = self._escaped_escaped.search(string)
130  self.beforebefore = string[:res.start()]
131  escape_chars = len(res.group(1))
132  self.backslashesbackslashes = '\\' * (escape_chars // 2)
133  self.escapedescaped = bool(escape_chars % 2)
134  self.texttext = res.group(2)
135  self.afterafter = string[res.end():]
136 
137 
138 def split_from_equals(string):
139  if not is_string(string) or '=' not in string:
140  return string, None
141  index = _get_split_index(string)
142  if index == -1:
143  return string, None
144  return string[:index], string[index+1:]
145 
146 def _get_split_index(string):
147  index = 0
148  while '=' in string[index:]:
149  index += string[index:].index('=')
150  if _not_escaping(string[:index]):
151  return index
152  index += 1
153  return -1
154 
155 def _not_escaping(name):
156  backslashes = len(name) - len(name.rstrip('\\'))
157  return backslashes % 2 == 0
def _unescape_character(self, text, length, escape)
Definition: escaping.py:101
def _get_character(self, text, length)
Definition: escaping.py:109