Merge lp:~jml/launchpad/import-fascist-tweaks into lp:launchpad

Proposed by Jonathan Lange
Status: Merged
Approved by: Muharem Hrnjadovic
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~jml/launchpad/import-fascist-tweaks
Merge into: lp:launchpad
Diff against target: 375 lines (+90/-54)
13 files modified
lib/canonical/launchpad/fields/__init__.py (+2/-0)
lib/lp/bugs/model/bugwatch.py (+1/-2)
lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py (+1/-0)
lib/lp/registry/interfaces/mailinglist.py (+1/-1)
lib/lp/registry/interfaces/teammembership.py (+1/-0)
lib/lp/registry/model/structuralsubscription.py (+3/-1)
lib/lp/scripts/utilities/importfascist.py (+66/-39)
lib/lp/services/job/interfaces/job.py (+1/-0)
lib/lp/soyuz/model/archive.py (+8/-4)
lib/lp/soyuz/model/archivesubscriber.py (+2/-2)
lib/lp/soyuz/model/builder.py (+2/-3)
lib/lp/soyuz/model/distroarchseries.py (+1/-2)
lib/lp/soyuz/model/files.py (+1/-0)
To merge this branch: bzr merge lp:~jml/launchpad/import-fascist-tweaks
Reviewer Review Type Date Requested Status
Muharem Hrnjadovic (community) Approve
Review via email: mp+16560@code.launchpad.net

Commit message

importfascist now checks 'lp' package and is now more data-driven. Many dodgy imports fixed.

To post a comment you must log in.
Revision history for this message
Jonathan Lange (jml) wrote :

This branch does a few different things, all to do with the import fascist. The patch:
  * restructures the logic to be a bit clearer.
  * provides a data-driven approach for allowing imports that aren't in __all__
  * makes importfascist check packages in 'lp' and not just 'canonical'
  * stops the warnings that we were all getting when running the tests
  * fixes a whole bunch of warnings that we weren't getting because of 'lp' being ignored
  * cleans up random pyflakes

Merry Christmas

Revision history for this message
Muharem Hrnjadovic (al-maisan) wrote :

Nice branch, approved with the changes in http://pastebin.ubuntu.com/345781/

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/fields/__init__.py'
--- lib/canonical/launchpad/fields/__init__.py 2009-12-09 23:11:31 +0000
+++ lib/canonical/launchpad/fields/__init__.py 2009-12-24 08:18:19 +0000
@@ -32,9 +32,11 @@
32 'LocationField',32 'LocationField',
33 'LogoImageUpload',33 'LogoImageUpload',
34 'MugshotImageUpload',34 'MugshotImageUpload',
35 'NoneableDescription',
35 'NoneableTextLine',36 'NoneableTextLine',
36 'ParticipatingPersonChoice',37 'ParticipatingPersonChoice',
37 'PasswordField',38 'PasswordField',
39 'PersonChoice',
38 'PillarAliases',40 'PillarAliases',
39 'PillarNameField',41 'PillarNameField',
40 'PrivateMembershipTeamNotAllowed',42 'PrivateMembershipTeamNotAllowed',
4143
=== modified file 'lib/lp/bugs/model/bugwatch.py'
--- lib/lp/bugs/model/bugwatch.py 2009-12-15 17:28:51 +0000
+++ lib/lp/bugs/model/bugwatch.py 2009-12-24 08:18:19 +0000
@@ -35,10 +35,9 @@
35from canonical.launchpad.webapp import urlappend, urlsplit35from canonical.launchpad.webapp import urlappend, urlsplit
36from canonical.launchpad.webapp.interfaces import NotFoundError36from canonical.launchpad.webapp.interfaces import NotFoundError
3737
38from lp.bugs.interfaces.bug import IBugWatch
39from lp.bugs.interfaces.bugtracker import BugTrackerType, IBugTrackerSet38from lp.bugs.interfaces.bugtracker import BugTrackerType, IBugTrackerSet
40from lp.bugs.interfaces.bugwatch import (39from lp.bugs.interfaces.bugwatch import (
41 BugWatchErrorType, IBugWatchSet, NoBugTrackerFound,40 BugWatchErrorType, IBugWatch, IBugWatchSet, NoBugTrackerFound,
42 UnrecognizedBugTrackerURL)41 UnrecognizedBugTrackerURL)
43from lp.bugs.model.bugmessage import BugMessage42from lp.bugs.model.bugmessage import BugMessage
44from lp.bugs.model.bugset import BugSetBase43from lp.bugs.model.bugset import BugSetBase
4544
=== modified file 'lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py'
--- lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py 2009-12-03 14:38:48 +0000
+++ lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py 2009-12-24 08:18:19 +0000
@@ -8,6 +8,7 @@
8__metaclass__ = type8__metaclass__ = type
99
10__all__ = [10__all__ = [
11 'BuildBehaviorMismatch',
11 'IBuildFarmJobBehavior',12 'IBuildFarmJobBehavior',
12 ]13 ]
1314
1415
=== modified file 'lib/lp/registry/interfaces/mailinglist.py'
--- lib/lp/registry/interfaces/mailinglist.py 2009-12-03 19:12:02 +0000
+++ lib/lp/registry/interfaces/mailinglist.py 2009-12-24 08:18:19 +0000
@@ -31,7 +31,7 @@
3131
32from canonical.launchpad import _32from canonical.launchpad import _
33from canonical.launchpad.fields import PublicPersonChoice33from canonical.launchpad.fields import PublicPersonChoice
34from lp.registry.interfaces.person import IEmailAddress34from canonical.launchpad.interfaces.emailaddress import IEmailAddress
35from canonical.launchpad.interfaces.librarian import ILibraryFileAlias35from canonical.launchpad.interfaces.librarian import ILibraryFileAlias
36from canonical.launchpad.interfaces.message import IMessage36from canonical.launchpad.interfaces.message import IMessage
37from lp.registry.interfaces.person import IPerson37from lp.registry.interfaces.person import IPerson
3838
=== modified file 'lib/lp/registry/interfaces/teammembership.py'
--- lib/lp/registry/interfaces/teammembership.py 2009-12-19 22:19:12 +0000
+++ lib/lp/registry/interfaces/teammembership.py 2009-12-24 08:18:19 +0000
@@ -14,6 +14,7 @@
14 'ITeamMembershipSet',14 'ITeamMembershipSet',
15 'ITeamParticipation',15 'ITeamParticipation',
16 'TeamMembershipStatus',16 'TeamMembershipStatus',
17 'UserCannotChangeMembershipSilently',
17 ]18 ]
1819
19from zope.schema import Bool, Choice, Datetime, Int, Text20from zope.schema import Bool, Choice, Datetime, Int, Text
2021
=== modified file 'lib/lp/registry/model/structuralsubscription.py'
--- lib/lp/registry/model/structuralsubscription.py 2009-12-05 18:37:28 +0000
+++ lib/lp/registry/model/structuralsubscription.py 2009-12-24 08:18:19 +0000
@@ -17,9 +17,11 @@
1717
18from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities18from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
19from lp.registry.interfaces.distribution import IDistribution19from lp.registry.interfaces.distribution import IDistribution
20from lp.registry.interfaces.distributionsourcepackage import (
21 IDistributionSourcePackage)
20from lp.registry.interfaces.distroseries import IDistroSeries22from lp.registry.interfaces.distroseries import IDistroSeries
21from lp.registry.interfaces.milestone import IMilestone23from lp.registry.interfaces.milestone import IMilestone
22from lp.registry.interfaces.product import IDistributionSourcePackage, IProduct24from lp.registry.interfaces.product import IProduct
23from lp.registry.interfaces.productseries import IProductSeries25from lp.registry.interfaces.productseries import IProductSeries
24from lp.registry.interfaces.project import IProject26from lp.registry.interfaces.project import IProject
25from lp.registry.interfaces.structuralsubscription import (27from lp.registry.interfaces.structuralsubscription import (
2628
=== modified file 'lib/lp/scripts/utilities/importfascist.py'
--- lib/lp/scripts/utilities/importfascist.py 2009-08-27 01:32:01 +0000
+++ lib/lp/scripts/utilities/importfascist.py 2009-12-24 08:18:19 +0000
@@ -52,6 +52,17 @@
52 """)52 """)
5353
5454
55# Sometimes, third-party modules don't export all of their public APIs through
56# __all__. The following dict maps from such modules to a list of attributes
57# that are allowed to be imported, whether or not they are in __all__.
58valid_imports_not_in_all = {
59 'cookielib': set(['domain_match']),
60 'email.Utils': set(['mktime_tz']),
61 'textwrap': set(['dedent']),
62 'zope.component': set(['adapter', 'provideHandler']),
63 }
64
65
55def database_import_allowed_into(module_path):66def database_import_allowed_into(module_path):
56 """Return True if database code is allowed to be imported into the given67 """Return True if database code is allowed to be imported into the given
57 module path. Otherwise, returns False.68 module path. Otherwise, returns False.
@@ -156,11 +167,11 @@
156167
157168
158# pylint: disable-msg=W0102,W0602169# pylint: disable-msg=W0102,W0602
159def import_fascist(name, globals={}, locals={}, fromlist=[]):170def import_fascist(module_name, globals={}, locals={}, from_list=[]):
160 global naughty_imports171 global naughty_imports
161172
162 try:173 try:
163 module = original_import(name, globals, locals, fromlist)174 module = original_import(module_name, globals, locals, from_list)
164 except ImportError:175 except ImportError:
165 # XXX sinzui 2008-04-17 bug=277274:176 # XXX sinzui 2008-04-17 bug=277274:
166 # import_fascist screws zope configuration module which introspects177 # import_fascist screws zope configuration module which introspects
@@ -170,19 +181,18 @@
170 # time doesn't exist and dies a horrible death because of the import181 # time doesn't exist and dies a horrible death because of the import
171 # fascist. That's the long explanation for why we special case this182 # fascist. That's the long explanation for why we special case this
172 # module.183 # module.
173 if name.startswith('zope.app.layers.'):184 if module_name.startswith('zope.app.layers.'):
174 name = name[16:]185 module_name = module_name[16:]
175 module = original_import(name, globals, locals, fromlist)186 module = original_import(module_name, globals, locals, from_list)
176 else:187 else:
177 raise188 raise
178 # Python's re module imports some odd stuff every time certain regexes189 # Python's re module imports some odd stuff every time certain regexes
179 # are used. Let's optimize this.190 # are used. Let's optimize this.
180 # Also, 'dedent' is not in textwrap.__all__.191 if module_name == 'sre':
181 if name == 'sre' or name == 'textwrap':
182 return module192 return module
183193
184 # Mailman 2.1 code base is originally circa 1998, so yeah, no __all__'s.194 # Mailman 2.1 code base is originally circa 1998, so yeah, no __all__'s.
185 if name.startswith('Mailman'):195 if module_name.startswith('Mailman'):
186 return module196 return module
187197
188 # Some uses of __import__ pass None for globals, so handle that.198 # Some uses of __import__ pass None for globals, so handle that.
@@ -195,13 +205,17 @@
195 # We could find out by jumping up the stack a frame.205 # We could find out by jumping up the stack a frame.
196 # Let's not for now.206 # Let's not for now.
197 import_into = '__import__ hook'207 import_into = '__import__ hook'
208
209 # Check the "NotFoundError" policy.
198 if (import_into.startswith('canonical.launchpad.database') and210 if (import_into.startswith('canonical.launchpad.database') and
199 name == 'zope.exceptions'):211 module_name == 'zope.exceptions'):
200 if fromlist and 'NotFoundError' in fromlist:212 if from_list and 'NotFoundError' in from_list:
201 raise NotFoundPolicyViolation(import_into)213 raise NotFoundPolicyViolation(import_into)
202 if (name.startswith(database_root) and214
215 # Check the database import policy.
216 if (module_name.startswith(database_root) and
203 not database_import_allowed_into(import_into)):217 not database_import_allowed_into(import_into)):
204 error = DatabaseImportPolicyViolation(import_into, name)218 error = DatabaseImportPolicyViolation(import_into, module_name)
205 naughty_imports.add(error)219 naughty_imports.add(error)
206 # Raise an error except in the case of browser.traversers.220 # Raise an error except in the case of browser.traversers.
207 # This exception to raising an error is only temporary, until221 # This exception to raising an error is only temporary, until
@@ -209,34 +223,48 @@
209 if import_into not in warned_database_imports:223 if import_into not in warned_database_imports:
210 raise error224 raise error
211225
212 if fromlist is not None and import_into.startswith('canonical'):226 # Check the import from __all__ policy.
227 if from_list is not None and (
228 import_into.startswith('canonical') or import_into.startswith('lp')):
213 # We only want to warn about "from foo import bar" violations in our229 # We only want to warn about "from foo import bar" violations in our
214 # own code.230 # own code.
215 if list(fromlist) == ['*'] and not hasattr(module, '__all__'):231 from_list = list(from_list)
216 # "from foo import *" is naughty if foo has no __all__232 module_all = getattr(module, '__all__', None)
217 error = FromStarPolicyViolation(import_into, name)233 if module_all is None:
218 naughty_imports.add(error)234 if from_list == ['*']:
219 raise error235 # "from foo import *" is naughty if foo has no __all__
220 elif (list(fromlist) != ['*'] and hasattr(module, '__all__') and236 error = FromStarPolicyViolation(import_into, module_name)
221 not is_test_module(import_into)):237 naughty_imports.add(error)
222 # "from foo import bar" is naughty if bar isn't in foo.__all__238 raise error
223 # (and foo actually has an __all__). Unless foo is within a tests239 else:
224 # or ftests module or bar is itself a module.240 if from_list == ['*']:
225 for attrname in fromlist:241 # "from foo import *" is allowed if foo has an __all__
226 if (attrname in ('adapter', 'provideHandler')242 return module
227 and module.__name__ == 'zope.component'):243 if is_test_module(import_into):
228 # 'adapter' and 'provideHandler' are not in244 # We don't bother checking imports into test modules.
229 # zope.component.__all__, but that's where they should be245 return module
230 # imported from.246 allowed_from_list = valid_imports_not_in_all.get(
231 continue247 module_name, set())
232 if attrname != '__doc__' and attrname not in module.__all__:248 for attrname in from_list:
233 if not isinstance(249 # Check that each thing we are importing into the module is
234 getattr(module, attrname, None), types.ModuleType):250 # either in __all__, is a module itself, or is a specific
235 error = NotInModuleAllPolicyViolation(251 # exception.
236 import_into, name, attrname)252 if attrname == '__doc__':
237 naughty_imports.add(error)253 # You can always import __doc__.
238 # Not raising on NotInModuleAllPolicyViolation yet.254 continue
239 #raise error255 if isinstance(
256 getattr(module, attrname, None), types.ModuleType):
257 # You can import modules even when they aren't declared in
258 # __all__.
259 continue
260 if attrname in allowed_from_list:
261 # Some things can be imported even if they aren't in
262 # __all__.
263 continue
264 if attrname not in module_all:
265 error = NotInModuleAllPolicyViolation(
266 import_into, module_name, attrname)
267 naughty_imports.add(error)
240 return module268 return module
241269
242270
@@ -244,7 +272,6 @@
244 if naughty_imports:272 if naughty_imports:
245 print273 print
246 print '** %d import policy violations **' % len(naughty_imports)274 print '** %d import policy violations **' % len(naughty_imports)
247 current_type = None
248275
249 database_violations = []276 database_violations = []
250 fromstar_violations = []277 fromstar_violations = []
251278
=== modified file 'lib/lp/services/job/interfaces/job.py'
--- lib/lp/services/job/interfaces/job.py 2009-09-02 21:09:48 +0000
+++ lib/lp/services/job/interfaces/job.py 2009-12-24 08:18:19 +0000
@@ -9,6 +9,7 @@
99
10__all__ = [10__all__ = [
11 'IJob',11 'IJob',
12 'IRunnableJob',
12 'JobStatus',13 'JobStatus',
13 'LeaseHeld',14 'LeaseHeld',
14 ]15 ]
1516
=== modified file 'lib/lp/soyuz/model/archive.py'
--- lib/lp/soyuz/model/archive.py 2009-12-08 15:40:23 +0000
+++ lib/lp/soyuz/model/archive.py 2009-12-24 08:18:19 +0000
@@ -54,7 +54,7 @@
54from lp.registry.model.teammembership import TeamParticipation54from lp.registry.model.teammembership import TeamParticipation
55from lp.soyuz.interfaces.archive import (55from lp.soyuz.interfaces.archive import (
56 AlreadySubscribed, ArchiveDependencyError, ArchiveNotPrivate,56 AlreadySubscribed, ArchiveDependencyError, ArchiveNotPrivate,
57 ArchivePurpose, DistroSeriesNotFound, IArchive, IArchiveSet,57 ArchivePurpose, CannotCopy, DistroSeriesNotFound, IArchive, IArchiveSet,
58 IDistributionArchive, InvalidComponent, IPPA, MAIN_ARCHIVE_PURPOSES,58 IDistributionArchive, InvalidComponent, IPPA, MAIN_ARCHIVE_PURPOSES,
59 NoSuchPPA, PocketNotFound, VersionRequiresName, default_name_by_purpose)59 NoSuchPPA, PocketNotFound, VersionRequiresName, default_name_by_purpose)
60from lp.soyuz.interfaces.archiveauthtoken import IArchiveAuthTokenSet60from lp.soyuz.interfaces.archiveauthtoken import IArchiveAuthTokenSet
@@ -77,7 +77,7 @@
77from lp.soyuz.interfaces.publishing import (77from lp.soyuz.interfaces.publishing import (
78 active_publishing_status, PackagePublishingStatus, IPublishingSet)78 active_publishing_status, PackagePublishingStatus, IPublishingSet)
79from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet79from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet
80from lp.soyuz.scripts.packagecopier import CannotCopy, do_copy80from lp.soyuz.scripts.packagecopier import do_copy
81from canonical.launchpad.webapp.interfaces import (81from canonical.launchpad.webapp.interfaces import (
82 IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR)82 IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR)
83from canonical.launchpad.webapp.url import urlappend83from canonical.launchpad.webapp.url import urlappend
@@ -1096,7 +1096,9 @@
1096 # Find and validate the source package names in source_names.1096 # Find and validate the source package names in source_names.
1097 sources = []1097 sources = []
1098 for name in source_names:1098 for name in source_names:
1099 source_package_name = getUtility(ISourcePackageNameSet)[name]1099 # Check to see if the source package exists, and raise a useful
1100 # error if it doesn't.
1101 getUtility(ISourcePackageNameSet)[name]
1100 # Grabbing the item at index 0 ensures it's the most recent1102 # Grabbing the item at index 0 ensures it's the most recent
1101 # publication.1103 # publication.
1102 sources.append(1104 sources.append(
@@ -1108,8 +1110,10 @@
1108 def syncSource(self, source_name, version, from_archive, to_pocket,1110 def syncSource(self, source_name, version, from_archive, to_pocket,
1109 to_series=None, include_binaries=False):1111 to_series=None, include_binaries=False):
1110 """See `IArchive`."""1112 """See `IArchive`."""
1113 # Check to see if the source package exists, and raise a useful error
1114 # if it doesn't.
1115 getUtility(ISourcePackageNameSet)[source_name]
1111 # Find and validate the source package version required.1116 # Find and validate the source package version required.
1112 source_package_name = getUtility(ISourcePackageNameSet)[source_name]
1113 source = from_archive.getPublishedSources(1117 source = from_archive.getPublishedSources(
1114 name=source_name, version=version, exact_match=True)[0]1118 name=source_name, version=version, exact_match=True)[0]
11151119
11161120
=== modified file 'lib/lp/soyuz/model/archivesubscriber.py'
--- lib/lp/soyuz/model/archivesubscriber.py 2009-07-17 00:26:05 +0000
+++ lib/lp/soyuz/model/archivesubscriber.py 2009-12-24 08:18:19 +0000
@@ -20,8 +20,8 @@
2020
21from canonical.database.constants import UTC_NOW21from canonical.database.constants import UTC_NOW
22from canonical.database.enumcol import DBEnum22from canonical.database.enumcol import DBEnum
23from lp.soyuz.model.archiveauthtoken import (23from lp.soyuz.interfaces.archiveauthtoken import IArchiveAuthTokenSet
24 ArchiveAuthToken, IArchiveAuthTokenSet)24from lp.soyuz.model.archiveauthtoken import ArchiveAuthToken
25from lp.registry.interfaces.person import (25from lp.registry.interfaces.person import (
26 validate_person_not_private_membership)26 validate_person_not_private_membership)
27from lp.registry.model.teammembership import TeamParticipation27from lp.registry.model.teammembership import TeamParticipation
2828
=== modified file 'lib/lp/soyuz/model/builder.py'
--- lib/lp/soyuz/model/builder.py 2009-12-04 12:49:25 +0000
+++ lib/lp/soyuz/model/builder.py 2009-12-24 08:18:19 +0000
@@ -42,8 +42,7 @@
42from lp.registry.interfaces.person import validate_public_person42from lp.registry.interfaces.person import validate_public_person
43from lp.registry.interfaces.pocket import PackagePublishingPocket43from lp.registry.interfaces.pocket import PackagePublishingPocket
44from canonical.launchpad.helpers import filenameToContentType44from canonical.launchpad.helpers import filenameToContentType
45from canonical.launchpad.interfaces._schema_circular_imports import (45from lp.soyuz.interfaces.buildrecords import IHasBuildRecords
46 IHasBuildRecords)
47from lp.soyuz.interfaces.distroarchseries import IDistroArchSeriesSet46from lp.soyuz.interfaces.distroarchseries import IDistroArchSeriesSet
48from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet47from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet
49from canonical.launchpad.webapp.interfaces import NotFoundError48from canonical.launchpad.webapp.interfaces import NotFoundError
@@ -380,7 +379,7 @@
380 return False379 return False
381 try:380 try:
382 slavestatus = self.slaveStatusSentence()381 slavestatus = self.slaveStatusSentence()
383 except (xmlrpclib.Fault, socket.error), info:382 except (xmlrpclib.Fault, socket.error):
384 return False383 return False
385 if slavestatus[0] != BuilderStatus.IDLE:384 if slavestatus[0] != BuilderStatus.IDLE:
386 return False385 return False
387386
=== modified file 'lib/lp/soyuz/model/distroarchseries.py'
--- lib/lp/soyuz/model/distroarchseries.py 2009-08-28 07:34:44 +0000
+++ lib/lp/soyuz/model/distroarchseries.py 2009-12-24 08:18:19 +0000
@@ -23,12 +23,11 @@
2323
24from canonical.launchpad.components.decoratedresultset import (24from canonical.launchpad.components.decoratedresultset import (
25 DecoratedResultSet)25 DecoratedResultSet)
26from canonical.launchpad.interfaces._schema_circular_imports import (
27 IHasBuildRecords)
28from lp.registry.interfaces.pocket import PackagePublishingPocket26from lp.registry.interfaces.pocket import PackagePublishingPocket
29from lp.soyuz.interfaces.binarypackagename import IBinaryPackageName27from lp.soyuz.interfaces.binarypackagename import IBinaryPackageName
30from lp.soyuz.interfaces.binarypackagerelease import IBinaryPackageReleaseSet28from lp.soyuz.interfaces.binarypackagerelease import IBinaryPackageReleaseSet
31from lp.soyuz.interfaces.build import IBuildSet29from lp.soyuz.interfaces.build import IBuildSet
30from lp.soyuz.interfaces.buildrecords import IHasBuildRecords
32from lp.soyuz.interfaces.distroarchseries import (31from lp.soyuz.interfaces.distroarchseries import (
33 IDistroArchSeries, IDistroArchSeriesSet, IPocketChroot)32 IDistroArchSeries, IDistroArchSeriesSet, IPocketChroot)
34from lp.soyuz.interfaces.publishing import (33from lp.soyuz.interfaces.publishing import (
3534
=== modified file 'lib/lp/soyuz/model/files.py'
--- lib/lp/soyuz/model/files.py 2009-11-25 23:41:34 +0000
+++ lib/lp/soyuz/model/files.py 2009-12-24 08:18:19 +0000
@@ -7,6 +7,7 @@
7__all__ = [7__all__ = [
8 'BinaryPackageFile',8 'BinaryPackageFile',
9 'BinaryPackageFileSet',9 'BinaryPackageFileSet',
10 'SourceFileMixin',
10 'SourcePackageReleaseFile',11 'SourcePackageReleaseFile',
11 ]12 ]
1213