152
152
comment_regex = re.compile(
153
153
"(?P<comment>(^#.+\n)+)(^import|^from) +(?P<module>[a-zA-Z0-9_.]+)", re.M)
154
154
split_regex = re.compile(",\s*")
155
module_base_regex = re.compile("([^. ]+)")
156
157
# Module docstrings are multiline (""") strings that are not indented and are
157
158
# followed at some point by an import .
290
'canonical', 'lp', 'launchpad_loggerhead', 'devscripts',
291
# database/* have some implicit relative imports.
292
'fti', 'replication', 'preflight', 'security', 'upgrade',
289
295
def format_imports(imports):
290
296
"""Group and order imports, return the new import statements."""
291
298
standard_section = {}
292
299
first_section = {}
293
300
thirdparty_section = {}
294
301
local_section = {}
295
302
# Group modules into sections.
296
303
for module, statement in imports.iteritems():
297
module_base = module.split('.')[0]
304
module_base = module_base_regex.findall(module)[0]
298
305
comment = statement.comment
299
if comment is not None and comment.startswith("# FIRST"):
306
if module_base == '_pythonpath':
307
early_section[module] = statement
308
elif comment is not None and comment.startswith("# FIRST"):
300
309
first_section[module] = statement
301
elif module_base in ('canonical', 'lp'):
310
elif module_base in LOCAL_PACKAGES:
302
311
local_section[module] = statement
303
312
elif module_base in python_standard_libs:
304
313
standard_section[module] = statement
339
349
imports_section = pyfile[import_start:import_end]
340
350
imports = parse_import_statements(imports_section)
342
if pyfile[import_end:import_end + 1] != '#':
352
next_char = pyfile[import_end:import_end + 1]
355
number_of_newlines = 1
356
elif next_char != '#':
343
357
# Two newlines before anything but comments.
344
358
number_of_newlines = 3