7 if sys.version_info.major == 3
and sys.version_info.minor >= 8:
9 return isinstance(el.value, ast.Constant)
11 get_source_segment = ast.get_source_segment
14 return isinstance(el.value, ast.Str)
17 """Get source code segment of the *source* that generated *node*. 18 If some location information (`lineno`, `end_lineno`, `col_offset`, 19 or `end_col_offset`) is missing, return None. 22 lineno = node.lineno - 1
23 end_lineno = node.end_lineno - 1
24 col_offset = node.col_offset
25 end_col_offset = node.end_col_offset
26 except AttributeError:
29 lines = ast._splitlines_no_ff(source)
30 if end_lineno == lineno:
31 return lines[lineno].encode()[col_offset:end_col_offset].decode()
33 first = lines[lineno].encode()[col_offset:].decode()
34 last = lines[end_lineno].encode()[:end_col_offset].decode()
35 lines = lines[lineno + 1:end_lineno]
37 lines.insert(0, first)
42 'catkin_pkg.python_setup':
'generate_distutils_setup' 45 IMPORT_TEMPLATE =
'from {} import {}\n' 46 QUOTE_CHARS = [
'"',
"'"]
51 """Convert a python collection (list/tuple/dict) to a sequence of lines, NOT including brackets 53 indent is the size of the indent 54 multi_line determines whether lists and tuples should be spread on multiple lines by default a la 55 multi_line=False : [1, 2, 3] 62 if isinstance(obj, dict):
64 for k, v
in obj.items():
67 joiner =
'\n' + (
' ' * 4)
68 s += joiner.join(sub_lines)
75 for line
in sub_lines[1:]:
76 s +=
'\n' +
' ' * (indent + 4) + line
85 line =
', '.join(items)
86 if indent + len(line) >= LINE_LENGTH:
89 return [item
for item
in items[:-1]] + [items[-1]]
95 """Convert a python object to the properly formatted python code. 97 initial_length is the length of the string before the object 98 indent is the size of the indent that each line should have 100 if isinstance(obj, list):
102 elif isinstance(obj, tuple):
104 elif isinstance(obj, dict)
or isinstance(obj, collections.OrderedDict):
114 if len(inner_lines) == 1
and '\n' not in inner_lines[0]:
115 inner_line = inner_lines[0]
116 if initial_length + len(inner_line) < LINE_LENGTH:
117 return [brackets[0] + inner_line + brackets[1]]
122 lines = [brackets[0]]
123 for line
in inner_lines:
125 line = line.replace(
'\n',
'\n ')
126 lines.append(
' ' + line)
127 lines.append(brackets[1])
132 """Utility function to wrap an arbitrary string in a quote character""" 133 return quote_char + s + quote_char
137 """Utility function to determine if the string is present in the container wrapped in some quote char""" 138 for quote_char
in QUOTE_CHARS:
140 if quoted_value
in container:
146 Representation of a setup.py file, covering a large range of different styles 148 The core operation is generating the dictionary of arguments sent to the setup function. 149 If a helper function (like generate_distutils_setup) is used, there won't be many arguments. 152 hash_bang (bool) - Whether the file starts with a #!/usr/bin/env python 153 imports (list of tuples) - Used for generating the import statements like `from X import Y` 154 First element of tuple is a string of the name of the module (e.g. X) 155 Second element is the string(s) representing the function(s) to import (e.g. Y) 156 declare_package_name (bool) - Whether to declare the package name as a string for later use 157 helper_function (optional string) - Name of module to find the helper function to call (see HELPER_FUNCTIONS) 158 helper_variable (optional string) - Name of variable to store the results of the helper function in. 159 args (ordered dictionary) - Arguments to pass to setup/helper_function 160 The keys are regular strings that represent the name of the variable. 161 The values are more complex. 168 self.
args = collections.OrderedDict()
173 self.
imports = [(
'distutils.core',
'setup'), (
'catkin_pkg.python_setup',
'generate_distutils_setup')]
181 original_contents = open(file_path,
'r').read() 183 self.
hash_bang = (original_contents[0] ==
'#')
192 for el
in ast.parse(original_contents).body:
193 if isinstance(el, ast.ImportFrom):
194 import_elements.append(el)
196 body_elements.append(el)
199 for el
in import_elements:
200 if el.module
in HELPER_FUNCTIONS:
202 self.
imports.append((el.module, [x.name
for x
in el.names]))
204 def ast_to_python(el):
205 """Helper function to convert an ast element to its Python data structure""" 206 if isinstance(el, ast.Dict):
208 for k, v
in zip(el.keys, el.values):
209 d[ast_to_python(k)] = ast_to_python(v)
211 elif isinstance(el, ast.List):
212 return [ast_to_python(elt)
for elt
in el.elts]
213 elif isinstance(el, ast.Tuple):
214 return tuple(ast_to_python(elt)
for elt
in el.elts)
219 for el
in body_elements:
220 if isinstance(el, ast.Assign):
226 for keyword
in el.value.keywords:
227 self.
args[keyword.arg] = ast_to_python(keyword.value)
230 for keyword
in el.value.keywords:
231 self.
args[keyword.arg] = ast_to_python(keyword.value)
243 s +=
'#!/usr/bin/env python\n\n' 245 for module, names
in self.
imports:
246 if isinstance(names, list):
247 names =
', '.join(sorted(names))
248 s += IMPORT_TEMPLATE.format(module, names)
253 s +=
"package_name = '{}'\n\n".format(self.
pkg_name)
263 for k, v
in self.
args.items():
264 line =
' {}='.format(k)
267 for line
in lines[1:]:
def quote_string(s, quote_char="'")
def contains_quoted_string(container, s)
def __init__(self, pkg_name, file_path)
def python_collection_to_lines(obj, indent=4, multi_line=False)
def python_to_lines(obj, initial_length=0, indent=4)