comparison roundup/anypy/strings.py @ 7766:c65e0a725c88

fix: replace eval with ast.literal_eval; ruff linting strings.py: When reading csv export files, use the safer literal_eval to evaluate the fields. Issue pointed out by ruff linter. Other Cleanup: sort imports replace if, else, if, else with if, elif, else use isinstance with tuples rather than 'isinstance() or isinstance()' test_anypy.py: Added tests for tuples, and booleans. Also added exception handling for malformed strings, booleans, tuples.
author John Rouillard <rouilj@ieee.org>
date Sat, 02 Mar 2024 04:01:22 -0500
parents 417c8ddc98ac
children 4261449081be
comparison
equal deleted inserted replaced
7765:dec7de56f253 7766:c65e0a725c88
2 # In Python 3, these are Unicode strings. In Python 2, these are 2 # In Python 3, these are Unicode strings. In Python 2, these are
3 # encoded using UTF-8, and the Python 2 unicode type is only used in a 3 # encoded using UTF-8, and the Python 2 unicode type is only used in a
4 # few places, generally for interacting with external modules 4 # few places, generally for interacting with external modules
5 # requiring that type to be used. 5 # requiring that type to be used.
6 6
7 import ast
8 import io
7 import sys 9 import sys
8 import io
9 10
10 _py3 = sys.version_info[0] > 2 11 _py3 = sys.version_info[0] > 2
11 12
12 if _py3: 13 if _py3:
13 StringIO = io.StringIO 14 StringIO = io.StringIO
61 62
62 def us2u(s, errors='strict'): 63 def us2u(s, errors='strict'):
63 """Convert a string or Unicode string to a Unicode string.""" 64 """Convert a string or Unicode string to a Unicode string."""
64 if _py3: 65 if _py3:
65 return s 66 return s
67 elif isinstance(s, unicode): # noqa: F821
68 return s
66 else: 69 else:
67 if isinstance(s, unicode): # noqa: F821 70 return unicode(s, 'utf-8', errors) # noqa: F821
68 return s
69 else:
70 return unicode(s, 'utf-8', errors) # noqa: F821
71 71
72 72
73 def us2s(u): 73 def us2s(u):
74 """Convert a string or Unicode string to the internal string format.""" 74 """Convert a string or Unicode string to the internal string format."""
75 if _py3: 75 if _py3:
76 return u 76 return u
77 elif isinstance(u, unicode): # noqa: F821
78 return u.encode('utf-8')
77 else: 79 else:
78 if isinstance(u, unicode): # noqa: F821 80 return u
79 return u.encode('utf-8')
80 else:
81 return u
82 81
83 82
84 def uany2s(u): 83 def uany2s(u):
85 """Convert a Unicode string or other object to the internal string format. 84 """Convert a Unicode string or other object to the internal string format.
86 85
87 Objects that are not Unicode strings are passed to str().""" 86 Objects that are not Unicode strings are passed to str()."""
88 if _py3: 87 if _py3:
89 return str(u) 88 return str(u)
89 elif isinstance(u, unicode): # noqa: F821
90 return u.encode('utf-8')
90 else: 91 else:
91 if isinstance(u, unicode): # noqa: F821 92 return str(u)
92 return u.encode('utf-8')
93 else:
94 return str(u)
95 93
96 94
97 def is_us(s): 95 def is_us(s):
98 """Return whether an object is a string or Unicode string.""" 96 """Return whether an object is a string or Unicode string."""
99 if _py3: 97 if _py3:
100 return isinstance(s, str) 98 return isinstance(s, str)
101 else: 99 else:
102 return isinstance(s, str) or isinstance(s, unicode) # noqa: F821 100 return isinstance(s, (str, unicode)) # noqa: F821
103 101
104 102
105 def uchr(c): 103 def uchr(c):
106 """Return the Unicode string containing the given character.""" 104 """Return the Unicode string containing the given character."""
107 if _py3: 105 if _py3:
139 return repr(v) 137 return repr(v)
140 138
141 139
142 def eval_import(s): 140 def eval_import(s):
143 """Evaluate a Python-2-style value imported from a CSV file.""" 141 """Evaluate a Python-2-style value imported from a CSV file."""
144 if _py3: 142 try:
145 try: 143 if _py3:
146 v = eval(s) 144 try:
147 except SyntaxError: 145 v = ast.literal_eval(s)
148 # handle case where link operation reports id a long int 146 except SyntaxError:
149 # ('issue', 5002L, "status") rather than as a string. 147 # handle case where link operation reports id a long
150 # This was a bug that existed and was fixed before or with v1.2.0 148 # int ('issue', 5002L, "status") rather than as a
151 import re 149 # string. This was a bug that existed and was fixed
152 v = eval(re.sub(r', ([0-9]+)L,', r', \1,', s)) 150 # before or with v1.2.0
151 import re
152 v = ast.literal_eval(re.sub(r', ([0-9]+)L,', r', \1,', s))
153 153
154 if isinstance(v, str): 154 if isinstance(v, str):
155 return v.encode('iso-8859-1').decode('utf-8') 155 return v.encode('iso-8859-1').decode('utf-8')
156 elif isinstance(v, dict): 156 elif isinstance(v, dict):
157 v_mod = {} 157 v_mod = {}
158 for key, value in v.items(): 158 # ruff: noqa: PLW2901
159 if isinstance(key, str): 159 for key, value in v.items():
160 key = key.encode('iso-8859-1').decode('utf-8') 160 if isinstance(key, str):
161 if isinstance(value, str): 161 key = key.encode('iso-8859-1').decode('utf-8')
162 value = value.encode('iso-8859-1').decode('utf-8') 162 if isinstance(value, str):
163 v_mod[key] = value 163 value = value.encode('iso-8859-1').decode('utf-8')
164 return v_mod 164 v_mod[key] = value
165 return v_mod
166 else:
167 return v
165 else: 168 else:
166 return v 169 return ast.literal_eval(s)
167 else: 170
168 return eval(s) 171 except (ValueError, SyntaxError) as e:
172 raise ValueError(
173 ("Error %(exception)s trying to parse value '%(value)s'") %
174 { 'exception': e, 'value': s})
175

Roundup Issue Tracker: http://roundup-tracker.org/