~launchpad-pqm/launchpad/devel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#!/usr/bin/python
#locate all the bad imports in zcml
#create  a set
#for each item in set
#find true path
#replace all occurences.

import os
import sys

from find import find_matches


def get_interfaces(types=None, globs=None):
    interfaces = set()
    root = 'lib'
    if types is None:
        types = r'\.(zcml)'
    if globs is None:
        globs = r'\bcanonical\.launchpad\.interfaces.(I\w*)\b'
    for summary in find_matches(root, types, globs):
        for line in summary['lines']:
            interfaces.add(line['match'].group(1))
    return interfaces


def get_interface_modules(interfaces):
    interface_modules = {}
    root = 'lib'
    types = r'(errors|enums|interfaces).*\.py'
    interface_def = r'\bclass (%s)\b'
    for interface in interfaces:
        for summary in find_matches(root, types, interface_def % interface):
            # Chop lib/ and .py from the string and repace the slash with dot.
            module_ = summary['file_path'][4:-3].replace('/', '.')
            interface_modules[interface] = module_
            break
    return interface_modules


def update_zcml_globs_to_interfaces():
    root = 'lib'
    types = r'\.(zcml)'
    globs = r'\bcanonical\.launchpad\.interfaces.(I\w*)\b'
    interfaces = get_interfaces(types=types, glob_interface=globs)
    interface_modules = get_interface_modules(interfaces)
    glob_interface = r'\b(canonical\.launchpad\.interfaces.%s)\b'
    for interface, module_ in interface_modules.items():
        pattern = glob_interface % interface
        substitution = '%s.%s' % (module_, interface)
        for summary in find_matches(
            root, types, pattern, substitution=substitution):
            print "\n%(file_path)s" % summary
            for line in summary['lines']:
                print "    %(lineno)4s: %(text)s" % line


def update_doctest_globs_to_interfaces():
    root = 'lib'
    types = r'\.(txt)'
    globs = r'from \bcanonical\.launchpad\.interfaces import (\w+)$'
    interfaces = get_interfaces(types=types, globs=globs)
    interface_modules = get_interface_modules(interfaces)
    glob_interface = r'\b(from canonical\.launchpad\.interfaces import %s)\b'
    for interface, module_ in interface_modules.items():
        pattern = glob_interface % interface
        substitution = 'from %s import %s' % (module_, interface)
        for summary in find_matches(
            root, types, pattern, substitution=substitution):
            print "\n%(file_path)s" % summary
            for line in summary['lines']:
                print "    %(lineno)4s: %(text)s" % line


def multiline_extract_match(file_path, match_re, substitution=None):
    """Return a summary of matches in a file."""
    lines = []
    content = []
    match = None
    file_ = open(file_path, 'r')
    in_match = False
    current_match = None
    try:
        for lineno, line in enumerate(file_):
            if in_match:
                identifiers = line.split(',')
                for idf in identifiers:
                    idf = idf.strip()
                    idf = idf.strip('...')
                    idf = idf.strip()
                    if idf.endswith(')'):
                        in_match = False
                        idf = idf[0:-1]
                    idf = idf.strip()
                    if idf == '':
                        continue
                    expanded_line = (
                        '%s %s\n' % (current_match.group(0), idf))
                    lines.append(
                        {'lineno': lineno + 1, 'text': expanded_line.strip(),
                         'match': None})
                    if substitution is not None:
                        content.append(expanded_line)
                    if not in_match:
                        current_match = None
                continue
            # Else check if this is the start of a multi-line.
            match = match_re.search(line)
            if match and line.strip().endswith('('):
                in_match = True
                current_match = match
                continue
            # Always append the non-matching lines to content to rebuild
            # the file.
            if substitution is not None:
                content.append(line)
    finally:
        file_.close()
    if lines:
        if substitution is not None:
            file_ = open(file_path, 'w')
            try:
                file_.write(''.join(content))
            finally:
                file_.close()
        return {'file_path': file_path, 'lines': lines}
    return None


def update_multi_doctest_globs_to_interfaces():
    root = 'lib'
    types = r'\.(txt)'
    pattern = r'[ ]+>>> from canonical\.launchpad\.interfaces import'
    substitution = True
    for summary in find_matches(
        root, types, pattern, substitution=substitution,
        extract_match=multiline_extract_match):
        print "\n%(file_path)s" % summary
        for line in summary['lines']:
            print "    %(lineno)4s: %(text)s" % line


def normalize_doctest_imports(file_path, match_re, substitution=None):
    """Return a summary of matches in a file."""
    lines = []
    content = []
    match = None
    file_ = open(file_path, 'r')
    in_match = False
    imports = None
    try:
        for lineno, line in enumerate(file_):
            match = match_re.search(line)
            # Start match imports.
            if match and not in_match:
                in_match = True
                whitespace = match.group(1)
                imports = {}
                # Fall-through.
            # Store the collected imports.
            if match:
                module_ = match.group(2)
                if module_ not in imports:
                    imports[module_] = []
                imports[module_].append(match.group(3))
                continue
            # If the import section is passed, normalize the imports.
            if not match and in_match:
                module_names = sorted(imports.keys())
                # Put zope modules first.
                zopes = list(module_names)
                zopes.reverse()
                for name in zopes:
                    if name.startswith('zope'):
                        module_names.remove(name)
                        module_names.insert(0, name)
                    else:
                        break
                for module_ in module_names:
                    identifiers = sorted(imports[module_])
                    if len(identifiers) == 1:
                        expanded_line = (
                            '%s>>> from %s import %s\n' %
                            (whitespace, module_, identifiers[0]))
                    else:
                        continuation = ',\n%s...     ' % whitespace
                        idfs = continuation.join(identifiers)
                        expanded_line = (
                            '%s>>> from %s import (%s%s%s)\n' %
                            (whitespace, module_,
                             continuation[1:], idfs, continuation))
                    lines.append(
                        {'lineno': lineno + 1, 'text': expanded_line.strip(),
                         'match': None})
                    if substitution is not None:
                        content.append(expanded_line)
                # Clear imports.
                in_match = False
                imports = None
                # Append the current line.
                if substitution is not None:
                    content.append(line)
                continue
            # Always append the non-matching lines to content to rebuild
            # the file.
            if substitution is not None:
                content.append(line)
    finally:
        file_.close()
    if lines:
        if substitution is not None:
            file_ = open(file_path, 'w')
            try:
                file_.write(''.join(content))
            finally:
                file_.close()
        return {'file_path': file_path, 'lines': lines}
    return None


def normalize_all_doctest_imports():
    root = 'lib'
    types = r'\.(txt)'
    pattern = r'^([ ]+)>>> from ([\w.]+) import ([\w.]+)$'
    substitution = True
    for summary in find_matches(
        root, types, pattern, substitution=substitution,
        extract_match=normalize_doctest_imports):
        print "\n%(file_path)s" % summary
        for line in summary['lines']:
            print "    %(lineno)4s: %(text)s" % line


def update_multi_python_globs_to_interfaces(root='lib', types='tests'):
    pattern=r'from canonical\.launchpad\.interfaces import'
    substitution = True
    for summary in find_matches(
        root, types, pattern, substitution=substitution,
        extract_match=multiline_extract_match):
        print "\n%(file_path)s" % summary
        for line in summary['lines']:
            print "    %(lineno)4s: %(text)s" % line


def update_python_globs_to_interfaces(root='lib', types='tests'):
    update_multi_python_globs_to_interfaces(root=root, types=types)
    globs = r'from \bcanonical\.launchpad\.interfaces import (\w+)$'
    interfaces = get_interfaces(types=types, globs=globs)
    interface_modules = get_interface_modules(interfaces)
    glob_interface = r'\b(from canonical\.launchpad\.interfaces import %s)\b'
    for interface, module_ in interface_modules.items():
        pattern = glob_interface % interface
        substitution = 'from %s import %s' % (module_, interface)
        for summary in find_matches(
            root, types, pattern, substitution=substitution):
            print "\n%(file_path)s" % summary
            for line in summary['lines']:
                print "    %(lineno)4s: %(text)s" % line


def main():
    if len(sys.argv) != 3:
        print 'Usage: %s root_path file_test', os.path.basename(sys.argv[0])
        sys.exit(1)
    root = sys.argv[1]
    types = sys.argv[2]
    update_python_globs_to_interfaces(root, types)


if __name__ == '__main__':
    main()