Merge lp:~adiroiban/launchpad/bug-525371 into lp:launchpad
- bug-525371
- Merge into devel
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 10953 | ||||
Proposed branch: | lp:~adiroiban/launchpad/bug-525371 | ||||
Merge into: | lp:launchpad | ||||
Diff against target: |
1034 lines (+338/-153) 18 files modified
lib/canonical/launchpad/interfaces/_schema_circular_imports.py (+18/-4) lib/canonical/launchpad/security.py (+11/-2) lib/lp/registry/configure.zcml (+0/-6) lib/lp/registry/interfaces/distroseries.py (+5/-3) lib/lp/registry/interfaces/productseries.py (+3/-1) lib/lp/registry/interfaces/sourcepackage.py (+8/-6) lib/lp/registry/model/distroseries.py (+5/-8) lib/lp/registry/model/productseries.py (+2/-4) lib/lp/registry/model/sourcepackage.py (+2/-4) lib/lp/registry/stories/webservice/xx-distroseries.txt (+2/-1) lib/lp/registry/stories/webservice/xx-project-registry.txt (+10/-5) lib/lp/translations/browser/potemplate.py (+11/-12) lib/lp/translations/interfaces/pofile.py (+12/-5) lib/lp/translations/interfaces/potemplate.py (+107/-82) lib/lp/translations/interfaces/webservice.py (+15/-0) lib/lp/translations/model/distroseries_translations_copy.py (+1/-1) lib/lp/translations/model/potemplate.py (+5/-9) lib/lp/translations/stories/webservice/xx-potemplate.txt (+121/-0) |
||||
To merge this branch: | bzr merge lp:~adiroiban/launchpad/bug-525371 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Данило Шеган (community) | Needs Fixing | ||
Jeroen T. Vermeulen | Pending | ||
Review via email: mp+25423@code.launchpad.net |
Commit message
Export POTemplate attributes in the API.
Description of the change
= Bug 525371 =
To help creating various translations statistics (ie for Ubuntu translations) it would be nice to have an LP API that could export the following information about a POTemplate:
* template name in Launchpad
* priority
* length
* date last updated
* domain name
* iscurrent (active or not)
* source package
* is in lang pack
* in how many languages it is translates (nice to have)
The API should return a list of all templates for a series, but also the info for a single template
The requirements are tracked on this wiki page:
https:/
== Proposed fix ==
This is the first step in implementing an API for POTemplates.
We will start with exposing the POTemplates attributes.
Here are the exported attributes:
active: True
all_
date_
description: None
exported_
format: u'PO format'
id: 2
language_count: 8
message_count: 63
name: u'pmount'
owner_link: u'http://
path: u'po/template.pot'
priority: 0
resource_
self_link: u'http://
translation
== Pre-implementation notes ==
During the last UDS I have talked with Henning and we had a pre-implementation talk.
He agreed with the current exported attributes. He said that he can not comment on the technical implementation details for the API.
If you think it is needed you can ask someone experienced with the LP API to review this branch.
== Implementation details ==
POFile API export is just a stub to illustrate how pofiles are linked to the corresponding po templates.
I don't know how to fix the /usr/share lint errors. Any hints are much appreciated.
== Tests ==
lib/lp/
lib/lp/
lib/lp/
lib/lp/
== Demo and Q/A ==
To get the potemplates for a sourcepackage
curl -ks https:/
To get the potemplates for a productseries
curl -ks https:/
To get the potemplates for a distroseries
curl -ks https:/
"all_translatio
curl -ks https:/
curl -ks https:/
curl -ks https:/
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files:
lib/lp/
== Pyflakes notices ==
lib/lp/
8: 'IHasTranslatio
8: 'ITranslationIm
8: 'ITranslationIm
13: 'IPOTemplate' imported but unused
15: 'IPOFile' imported but unused
warning: Not importing directory '/usr/share/
warning: Not importing directory '/usr/share/
warning: Not importing directory '/usr/share/
Jeroen T. Vermeulen (jtv) wrote : | # |
Adi Roiban (adiroiban) wrote : | # |
Hi,
I have improved the tests to check for templates count from the db.
Here is the latest diff:
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -107,9 +107,19 @@
All templates associated to a distribution series are available at the
'all_translati
+ >>> from zope.component import getUtility
+ >>> from canonical.
+ ... ILaunchpadCeleb
+ >>> from lp.translations
+ >>> login('<email address hidden>')
+ >>> hoary = getUtility(
+ >>> templates = getUtility(
+ >>> db_count = len(list(
+ >>> logout()
>>> all_translation
... '/ubuntu/
- >>> print all_translation
- 6
+ >>> api_count = all_translation
+ >>> api_count == db_count
+ True
>>> print(all_
http://
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -897,11 +897,20 @@
"all_translati
product series.
+
+ >>> from zope.component import getUtility
+ >>> from lp.translations
+ >>> login('<email address hidden>')
+ >>> templates = getUtility(
+ ... IPOTemplateSet)
+ >>> db_count = len(list(
+ >>> logout()
>>> all_translation
... babadoo_foobadoo[
... 'all_translatio
- >>> print all_translation
- 1
+ >>> api_count = all_translation
+ >>> api_count == db_count
+ True
>>> print(all_
http://
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -130,10 +130,27 @@
All translation templates for a source package are available at the
'all_translati
+
+ >>> from zope.component import getUtility
+ >>> from canonical.
+ ... ILaunchpadCeleb
+ >>> from lp.registry.
+ ... ISourcePackageN
+ >>> from lp.translations
+ >...
Данило Шеган (danilo) wrote : | # |
Hi Adi,
Thanks a lot for the work on this. Overall, it's pretty good.
У пон, 17. 05 2010. у 11:07 +0000, Adi Roiban пише:
> == Tests ==
>
> lib/lp/
> lib/lp/
> lib/lp/
> lib/lp/
It usually helps if you provide a bin/test command which runs them for
lazy reviewers to copy-paste them :)
> == Demo and Q/A ==
>
> To get the potemplates for a sourcepackage
> curl -ks
https:/
>
> To get the potemplates for a productseries
> curl -ks
https:/
>
> To get the potemplates for a distroseries
> curl -ks
https:/
>
> "all_translatio
distroseries and productseries
> curl -ks
https:/
> curl -ks https:/
> curl -ks https:/
>
> = Launchpad lint =
>
> Checking for conflicts. and issues in doctests and templates.
> Running jslint, xmllint, pyflakes, and pylint.
> Using normal rules.
>
> Linting changed files:
> lib/lp/
There are many more files with many more lint issues: you should try to
run it after you commit your final change, not before (if you've got
uncommitted changes, it lints just the uncommitted files). Please fix
all the issues.
> == Pyflakes notices ==
>
> lib/lp/
> 8: 'IHasTranslatio
> 8: 'ITranslationIm
> 8: 'ITranslationIm
> 13: 'IPOTemplate' imported but unused
> 15: 'IPOFile' imported but unused
You should add the following to webservice.py if that's the intention:
__all__ = [
'IHasTransl
'IPOFile',
'IPOTemplate',
'ITranslati
'ITranslati
]
But, why is this necessary?
> warning: Not importing directory '/usr/share/
__init__.py
> warning: Not importing directory '/usr/share/
__init__.py
> warning: Not importing directory '/usr/share/
__init__.py
This might be a bug in lazr that needs fixing. Can you please check and
file appropriate bug if it is?
> === modified file 'lib/canonical/
> --- lib/canonical/
+0000
> +++ lib/canonical/
+0000
> @@ -61,8 +61,7 @@ from lp.hardwaredb.
> from lp.services.
ILanguageSet
> from lp.translations
> from canonical.
> - IBazaarApplication, IHasBug, IHasDrivers, ILaunchpadCeleb
> - IPersonRoles)
> + IHas...
Данило Шеган (danilo) : | # |
Adi Roiban (adiroiban) wrote : | # |
On Wed, 2010-05-19 at 14:43 +0000, Данило Шеган wrote:
> Hi Adi,
>
> Thanks a lot for the work on this. Overall, it's pretty good.
>
> У пон, 17. 05 2010. у 11:07 +0000, Adi Roiban пише:
>
> > == Tests ==
> >
> > lib/lp/
> > lib/lp/
> > lib/lp/
> > lib/lp/
>
> It usually helps if you provide a bin/test command which runs them for
> lazy reviewers to copy-paste them :)
Sorry. I will add it with the next MP.
./bin/test -t xx-potemplate.txt -t xx-distroseries.txt \
-t xx-project-
:)
[snip]
> > = Launchpad lint =
> >
> > Checking for conflicts. and issues in doctests and templates.
> > Running jslint, xmllint, pyflakes, and pylint.
> > Using normal rules.
> >
> > Linting changed files:
> > lib/lp/
>
> There are many more files with many more lint issues: you should try to
> run it after you commit your final change, not before (if you've got
> uncommitted changes, it lints just the uncommitted files). Please fix
> all the issues.
I have fixed some of the other warning.
There are still some warnings for code like:
@operation_
and it looks fine to me, but pylint complains about:
lib/lp/
191: [C0322, ISourcePackage.
space
required=True,
^
vocabulary=
> > == Pyflakes notices ==
> >
> > lib/lp/
> > 8: 'IHasTranslatio
> > 8: 'ITranslationIm
> > 8: 'ITranslationIm
> > 13: 'IPOTemplate' imported but unused
> > 15: 'IPOFile' imported but unused
>
> You should add the following to webservice.py if that's the intention:
>
> __all__ = [
> 'IHasTranslatio
> 'IPOFile',
> 'IPOTemplate',
> 'ITranslationIm
> 'ITranslationIm
> ]
>
> But, why is this necessary?
Only interfaces listed in webservices.py will be exported by
lazr.restful.
Adding __all__ will still generate Pyflakes notices as they are still
unused in that file.
> > warning: Not importing directory '/usr/share/
> __init__.py
> > warning: Not importing directory '/usr/share/
> __init__.py
> > warning: Not importing directory '/usr/share/
> __init__.py
>
> This might be a bug in lazr that needs fixing. Can you please check and
> file appropriate bug if it is?
Is is not a problem in lazr. I have the same problem with:
'/usr/share/
Those file were installed as dependencies for ubuntuone-
python-protobuf and python-lazr-uri, python-
maintained by main Ubuntu developers... not in the LP PPA.
> > === modified file 'lib/...
Данило Шеган (danilo) wrote : | # |
Hi Adi,
Thanks for the updates. There's still just a little bit more to do :)
У сре, 19. 05 2010. у 20:13 +0000, Adi Roiban пише:
> There are still some warnings for code like:
>
> @operation_
> pocket=Choice(
> title=_("Pocket"), required=True,
> vocabulary=
>
> and it looks fine to me, but pylint complains about:
>
> lib/lp/
> 191: [C0322, ISourcePackage.
> space
> required=True,
> ^
> vocabulary=
>
>
> > > == Pyflakes notices ==
> > >
> > > lib/lp/
> > > 8: 'IHasTranslatio
> > > 8: 'ITranslationIm
> > > 8: 'ITranslationIm
> > > 13: 'IPOTemplate' imported but unused
> > > 15: 'IPOFile' imported but unused
> >
> > You should add the following to webservice.py if that's the intention:
> >
> > __all__ = [
> > 'IHasTranslatio
> > 'IPOFile',
> > 'IPOTemplate',
> > 'ITranslationIm
> > 'ITranslationIm
> > ]
> >
> > But, why is this necessary?
>
> Only interfaces listed in webservices.py will be exported by
> lazr.restful.
>
> Adding __all__ will still generate Pyflakes notices as they are still
> unused in that file.
It actually fixed it for me. I'm attaching a patch which fixes all the
lint issues I've seen. It would be nicer if you did that instead :)
Also, "operator not preceded by space" lint issues in this particular
context seem to be opposed to our style guide. It would be best to
raise this on launchpad-dev mailing list to come to an agreement and to
see if we can fix either pylint or style guide.
> > > warning: Not importing directory '/usr/share/
> > __init__.py
> > > warning: Not importing directory '/usr/share/
> > __init__.py
> > > warning: Not importing directory '/usr/share/
> > __init__.py
> >
> > This might be a bug in lazr that needs fixing. Can you please check and
> > file appropriate bug if it is?
>
> Is is not a problem in lazr. I have the same problem with:
> '/usr/share/
>
> Those file were installed as dependencies for ubuntuone-
> python-protobuf and python-lazr-uri, python-
> maintained by main Ubuntu developers... not in the LP PPA.
Well, LAZR is a library shared between Launchpad and UbuntuOne. It's
still a bug that would need to be filed. I've worked-around it locally
by doing "sudo touch /usr/share/
probably no reason why the package shouldn't do the same for everybody.
> Should POTemplate and POFile API be available only to authenticated
> users?
Not, it's fine if they are anonymously available.
> > === modified file
> > 'lib/lp/
> > === modified file
> > 'lib/lp/
> > === modified file
> > 'lib/lp/
1 | === modified file 'lib/lp/registry/interfaces/distroseries.py' |
2 | --- lib/lp/registry/interfaces/distroseries.py 2010-05-19 17:04:11 +0000 |
3 | +++ lib/lp/registry/interfaces/distroseries.py 2010-05-20 16:10:38 +0000 |
4 | @@ -114,7 +114,7 @@ class DistroSeriesVersionField(UniqueFie |
5 | |
6 | def _validate(self, version): |
7 | """See `UniqueField`.""" |
8 | - super(DistroSeriesVersionField, self)._validate(version) |
9 | + DistroSeriesVersionField._validate(self, version) |
10 | if not sane_version(version): |
11 | raise LaunchpadValidationError( |
12 | "%s is not a valid version" % version) |
13 | @@ -423,38 +423,38 @@ class IDistroSeriesPublic( |
14 | |
15 | @operation_parameters( |
16 | created_since_date=Datetime( |
17 | - title=_("Created Since Timestamp"), |
18 | - description=_( |
19 | + title = _("Created Since Timestamp"), |
20 | + description = _( |
21 | "Return items that are more recent than this timestamp."), |
22 | - required=False), |
23 | + required = False), |
24 | status=Choice( |
25 | # Really PackageUploadCustomFormat, patched in |
26 | # _schema_circular_imports.py |
27 | - vocabulary=DBEnumeratedType, |
28 | - title=_("Package Upload Status"), |
29 | - description=_("Return only items that have this status."), |
30 | - required=False), |
31 | + vocabulary = DBEnumeratedType, |
32 | + title = _("Package Upload Status"), |
33 | + description = _("Return only items that have this status."), |
34 | + required = False), |
35 | archive=Reference( |
36 | # Really IArchive, patched in _schema_circular_imports.py |
37 | - schema=Interface, |
38 | - title=_("Archive"), |
39 | - description=_("Return only items for this archive."), |
40 | - required=False), |
41 | + schema = Interface, |
42 | + title = _("Archive"), |
43 | + description = _("Return only items for this archive."), |
44 | + required = False), |
45 | pocket=Choice( |
46 | # Really PackagePublishingPocket, patched in |
47 | # _schema_circular_imports.py |
48 | - vocabulary=DBEnumeratedType, |
49 | - title=_("Pocket"), |
50 | - description=_("Return only items targeted to this pocket"), |
51 | - required=False), |
52 | + vocabulary = DBEnumeratedType, |
53 | + title = _("Pocket"), |
54 | + description = _("Return only items targeted to this pocket"), |
55 | + required = False), |
56 | custom_type=Choice( |
57 | # Really PackageUploadCustomFormat, patched in |
58 | # _schema_circular_imports.py |
59 | - vocabulary=DBEnumeratedType, |
60 | - title=_("Custom Type"), |
61 | - description=_("Return only items with custom files of this " |
62 | + vocabulary = DBEnumeratedType, |
63 | + title = _("Custom Type"), |
64 | + description = _("Return only items with custom files of this " |
65 | "type."), |
66 | - required=False), |
67 | + required = False) |
68 | ) |
69 | # Really IPackageUpload, patched in _schema_circular_imports.py |
70 | @operation_returns_collection_of(Interface) |
71 | |
72 | === modified file 'lib/lp/registry/interfaces/sourcepackage.py' |
73 | --- lib/lp/registry/interfaces/sourcepackage.py 2010-05-17 10:16:03 +0000 |
74 | +++ lib/lp/registry/interfaces/sourcepackage.py 2010-05-20 16:13:43 +0000 |
75 | @@ -187,8 +187,8 @@ class ISourcePackage(IBugTarget, IHasBra |
76 | # in _schema_circular_imports. |
77 | @operation_parameters( |
78 | pocket=Choice( |
79 | - title=_("Pocket"), required=True, |
80 | - vocabulary=DBEnumeratedType)) |
81 | + title = _("Pocket"), required = True, |
82 | + vocabulary = DBEnumeratedType)) |
83 | # Actually returns an IBranch, but we say Interface here to avoid circular |
84 | # imports. Correct interface specified in _schema_circular_imports. |
85 | @operation_returns_entry(Interface) |
86 | @@ -205,9 +205,9 @@ class ISourcePackage(IBugTarget, IHasBra |
87 | # imports. Correct interface specific in _schema_circular_imports. |
88 | @operation_parameters( |
89 | pocket=Choice( |
90 | - title=_("Pocket"), required=True, |
91 | - vocabulary=DBEnumeratedType), |
92 | - branch=Reference(Interface, title=_("Branch"), required=False)) |
93 | + title = _("Pocket"), required = True, |
94 | + vocabulary = DBEnumeratedType), |
95 | + branch = Reference(Interface, title = _("Branch"), required = False)) |
96 | @call_with(registrant=REQUEST_USER) |
97 | @export_write_operation() |
98 | def setBranch(pocket, branch, registrant): |
99 | |
100 | === modified file 'lib/lp/translations/interfaces/webservice.py' |
101 | --- lib/lp/translations/interfaces/webservice.py 2010-05-18 15:27:05 +0000 |
102 | +++ lib/lp/translations/interfaces/webservice.py 2010-05-20 16:02:50 +0000 |
103 | @@ -14,3 +14,11 @@ from lp.translations.interfaces.potempla |
104 | IPOTemplate) |
105 | from lp.translations.interfaces.pofile import ( |
106 | IPOFile) |
107 | + |
108 | +__all__ = [ |
109 | + 'IHasTranslationImports', |
110 | + 'IPOFile', |
111 | + 'IPOTemplate', |
112 | + 'ITranslationImportQueue', |
113 | + 'ITranslationImportQueueEntry', |
114 | + ] |
115 | |
116 | === modified file 'lib/lp/translations/model/potemplate.py' |
117 | --- lib/lp/translations/model/potemplate.py 2010-05-17 10:16:03 +0000 |
118 | +++ lib/lp/translations/model/potemplate.py 2010-05-20 16:19:09 +0000 |
119 | @@ -1297,8 +1297,8 @@ class POTemplateSet: |
120 | elif sourcepackagename is None: |
121 | # Multiple matches, and for a product not a package. |
122 | logging.warn( |
123 | - "Found %d templates with path '%s' for productseries %s" % ( |
124 | - len(matches), path, productseries.title)) |
125 | + "Found %d templates with path '%s' for productseries %s", |
126 | + len(matches), path, productseries.title) |
127 | return None |
128 | else: |
129 | # Multiple matches, for a distribution package. Prefer a |
130 | @@ -1316,9 +1316,9 @@ class POTemplateSet: |
131 | else: |
132 | logging.warn( |
133 | "Found %d templates with path '%s' for package %s " |
134 | - "(%d matched on from_sourcepackagename)." % ( |
135 | - len(matches), path, sourcepackagename.name, |
136 | - len(preferred_matches))) |
137 | + "(%d matched on from_sourcepackagename).", |
138 | + len(matches), path, sourcepackagename.name, |
139 | + len(preferred_matches)) |
140 | return None |
141 | |
142 | @staticmethod |
143 | @@ -1510,10 +1510,6 @@ class POTemplateToTranslationFileDataAda |
144 | if flag |
145 | ]) |
146 | |
147 | - # Store sequences so we can detect later whether we changed the |
148 | - # message. |
149 | - sequence = row.sequence |
150 | - |
151 | # Store the message. |
152 | messages.append(msgset) |
153 | |
154 |
Adi Roiban (adiroiban) wrote : | # |
On Thu, 2010-05-20 at 16:33 +0000, Данило Шеган wrote:
> Hi Adi,
>
> Thanks for the updates. There's still just a little bit more to do :)
>
> У сре, 19. 05 2010. у 20:13 +0000, Adi Roiban пише:
>
> > There are still some warnings for code like:
> >
> > @operation_
> > pocket=Choice(
> > title=_("Pocket"), required=True,
> > vocabulary=
> >
> > and it looks fine to me, but pylint complains about:
> >
> > lib/lp/
> > 191: [C0322, ISourcePackage.
> > space
> > required=True,
> > ^
> > vocabulary=
> >
> >
> > > > == Pyflakes notices ==
> > > >
> > > > lib/lp/
> > > > 8: 'IHasTranslatio
> > > > 8: 'ITranslationIm
> > > > 8: 'ITranslationIm
> > > > 13: 'IPOTemplate' imported but unused
> > > > 15: 'IPOFile' imported but unused
> > >
> > > You should add the following to webservice.py if that's the intention:
> > >
> > > __all__ = [
> > > 'IHasTranslatio
> > > 'IPOFile',
> > > 'IPOTemplate',
> > > 'ITranslationIm
> > > 'ITranslationIm
> > > ]
> > >
> > > But, why is this necessary?
> >
> > Only interfaces listed in webservices.py will be exported by
> > lazr.restful.
> >
> > Adding __all__ will still generate Pyflakes notices as they are still
> > unused in that file.
>
> It actually fixed it for me. I'm attaching a patch which fixes all the
> lint issues I've seen. It would be nicer if you did that instead :)
I have no idea why this is not fixing for me.
Here is the output for `make lint` after applying your patch:
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files:
lib/lp/
lib/lp/
lib/lp/
lib/lp/
== Pyflakes notices ==
lib/lp/
16: 'IHasTranslatio
16: 'ITranslationIm
16: 'ITranslationIm
21: 'IPOTemplate' imported but unused
23: 'IPOFile' imported but unused
> Also, "operator not preceded by space" lint issues in this particular
> context seem to be opposed to our style guide. It would be best to
> raise this on launchpad-dev mailing list to come to an agreement and to
> see if we can fix either pylint or style guide.
I have sent and email to lp-dev ML.
> > > > warning: Not importing directory '/usr/share/
> > > __init__.py
> > > > warning: Not importing directory '/usr/share/
> > > __init__.py
> > > > warning: Not importing directory '/usr/share/
> > > __init__.py
> > >
> > > This might be a bug in lazr that needs fixing. Can you please check and
> > > file app...
Данило Шеган (danilo) wrote : | # |
Hey Adi, we are getting very close. Just a few more small issues to
fix.
У чет, 20. 05 2010. у 18:00 +0000, Adi Roiban пише:
> > It actually fixed it for me. I'm attaching a patch which fixes all the
> > lint issues I've seen. It would be nicer if you did that instead :)
>
> I have no idea why this is not fixing for me.
>
> Here is the output for `make lint` after applying your patch:
>
> = Launchpad lint =
>
> Checking for conflicts. and issues in doctests and templates.
> Running jslint, xmllint, pyflakes, and pylint.
> Using normal rules.
>
> Linting changed files:
> lib/lp/
> lib/lp/
> lib/lp/
> lib/lp/
>
> == Pyflakes notices ==
>
> lib/lp/
> 16: 'IHasTranslatio
> 16: 'ITranslationIm
> 16: 'ITranslationIm
> 21: 'IPOTemplate' imported but unused
> 23: 'IPOFile' imported but unused
Hum, very interesting. Perhaps it's a problem with pyflakes
incompatibilities? (FWIW, it seems your branch now specifies __all__
twice)
FWIW, defining __all__ fixes pyflakes warnings for me, but not the
pylint warnings.
> > Also, "operator not preceded by space" lint issues in this particular
> > context seem to be opposed to our style guide. It would be best to
> > raise this on launchpad-dev mailing list to come to an agreement and to
> > see if we can fix either pylint or style guide.
>
> I have sent and email to lp-dev ML.
Cool. It seems everybody agrees that we should not change the
styleguide, but instead not use pylint as is. You can ignore those
warnings and revert that bit of my patch. It'd still be very useful to
resolve the pyflakes warnings that you are getting, though.
> I have filled a bug report for that:
> https:/
Excellent, thanks a lot.
> [snip]
> >
> > > > > === modified file 'lib/lp/
> > > > ...
> > > > > source_file = Object(
> > > > > title=_('Source file for this translation template'),
> > > > > readonly=True, schema=
> > > >
> > > > I don't remember why we decided not to export this one? It could be
> > > > useful for things like xpipo conversion (with XPI-based translations,
> > > > it should contain a reference to imported en-US.xpi).
> > > >
> > > > Though, we should probably just export it as the public URL, so not a
> > > > big deal (let's not block this branch on this).
> > >
> > > I will leave it for another branch, but for me, it would make sense if
> > > this attribute would be used for all translation templates, not only
> > > XPI.
> >
> > Well, we can reconstruct the gettext POT file completely from what we
> > have in the DB. Thus, it's not needed.
>
> My note was about creating a more consistent API so that in the API
> source_file (or whatever name we choose for it) would return the
> template file for all formats, not only XPI.
Sure...
> Instead of...
Adi Roiban (adiroiban) wrote : | # |
On Thu, 2010-05-20 at 18:48 +0000, Данило Шеган wrote:
> Hey Adi, we are getting very close. Just a few more small issues to
> fix.
>
> У чет, 20. 05 2010. у 18:00 +0000, Adi Roiban пише:
>
> > > It actually fixed it for me. I'm attaching a patch which fixes all the
> > > lint issues I've seen. It would be nicer if you did that instead :)
> >
> > I have no idea why this is not fixing for me.
> >
> > Here is the output for `make lint` after applying your patch:
> >
> > = Launchpad lint =
> >
> > Checking for conflicts. and issues in doctests and templates.
> > Running jslint, xmllint, pyflakes, and pylint.
> > Using normal rules.
> >
> > Linting changed files:
> > lib/lp/
> > lib/lp/
> > lib/lp/
> > lib/lp/
> >
> > == Pyflakes notices ==
> >
> > lib/lp/
> > 16: 'IHasTranslatio
> > 16: 'ITranslationIm
> > 16: 'ITranslationIm
> > 21: 'IPOTemplate' imported but unused
> > 23: 'IPOFile' imported but unused
>
> Hum, very interesting. Perhaps it's a problem with pyflakes
> incompatibilities? (FWIW, it seems your branch now specifies __all__
> twice)
>
> FWIW, defining __all__ fixes pyflakes warnings for me, but not the
> pylint warnings.
I have removed the duplicate __all__ and only leave it before the
imports.
[snip]
> > > Add __all__: have you tried it at all? It totally works for me, and I'd
> > > be very surprised if it doesn't work for you. Also, __all__ is required
> > > in all our modules as well (importfascist used to check that before,
> > > maybe it doesn't anymore)
>
> I'd really like to get this resolved. It seems the line length is also
> slightly differently defined for you:
>
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -127,9 +127,9 @@
> '''),
> required=False)
>
> - translation_
> - All `ITranslationMe
> - '''))
> + translation_
> + "All `ITranslationMe
> + "translation file."))
>
> plural_forms = Int(
> title=_('Number of plural forms for the language of this PO file.'),
>
>
> This is not needed for me, because just putting it as
>
> translation_
> 'All `ITranslationMe
> ))
>
> works fine. Not that there's anything wrong with your approach, I am just noting this.
This will break the styleguide as there is a space before the ')'
> > > > === modified file 'lib/lp/
> > > > --- lib/lp/
> > > > +++ lib/lp/
Данило Шеган (danilo) wrote : | # |
Hi Adi,
У чет, 20. 05 2010. у 19:06 +0000, Adi Roiban пише:
> > This is not needed for me, because just putting it as
> >
> > translation_
> > 'All `ITranslationMe
> > ))
> >
> > works fine. Not that there's anything wrong with your approach, I am just noting this.
>
> This will break the styleguide as there is a space before the ')'
Heh, this is not really a space: it's a multiline wrapping of braces,
and we do exactly the same thing with tuples (we'd do it with imports as
well if we didn't have too many of those), as mentioned on [1]:
something = (
FirstVery
SecondVer
)
[1] https:/
Anyway, as I said, your style is just as fine as well.
review approve
merge approve
I'll get this into ec2 land soon.
Cheers,
Danilo
Данило Шеган (danilo) wrote : | # |
Hi Adi,
Ok, I realized there are more things to fix first. We've discussed them
over on IRC, but I will repeat myself a bit for reference.
review needs-fixing
Attribute names should include as little gettextisms as possible:
"all_pofiles" and "all_potemplates" should be "translation_files" and
"translation_
branch: I am not sure about the "all").
And further on that topic, we should only show most relevant translation
templates: these are usually only the current, non-obsolete ones.
Obsolete templates are useful only for management purposes, and if we
want, we can export them either separately, or export all of
getCurrentTra
getObsoleteTr
getTranslatio
There is no need to wrap either of the methods in a property in order to
export them. What's else, these methods expose some implementation
details (like "just_ids" parameter, needed for performance reasons
elsewhere) and we should not get them exported as such.
Since I want to see this branch move in soon, I don't want to dwell on
cleaning up these right now.
Now, performance reasons are very important to consider here. We may
have to investigate whether `doNotSnapshot` is needed, and how batching
works over Collection results ([1] suggests it splits results into
batches of 75, but we'd have to check that). If API framework splits
the results into batches and only serializes a single batch (vs
serializing a whole result set), it'd be ok even if we don't use
doNotSnapshot (unless it turns out to be too slow once it hits
edge/staging, when we'll need to fix it).
Also, at the moment, we should export only the most useful list of
templates (because most of this code needs slight refactoring, we should
not export all methods and then stop exporting them soon after). At the
moment, for the "reporting" use case, I believe only "current" templates
make sense to be exported. Now, exporting it with just_ids parameter is
fine as well, and we can fix it with the refactoring in the future.
Next, we did mention how it should already allow read-write access if
you've got sufficient privileges. In my tests that has turned out to be
false. This is definitely not a blocker (it's ok if we start with
read-only API), but we at least need to understand why this is so and
how is write access created (so we don't do it by accident).
Example script I tried out (after doing 'make run' in this branch, run
this in a python console and log in with sufficient privileges, eg.
<email address hidden>:test):
cachedir = "/home/
from launchpadlib.
launchpad = Launchpad.
ubuntu = launchpad.
hoary = ubuntu.series[2]
pots = hoary.all_
pot = pots[0]
pot.translati
pot.lp_save()
So, suggested course of action to get this landed:
0. fix "all_pofile" attribute name
1. Check if we get batching of results on API method calls/attributes
for free (without needing to do anything else)
2. If 1 is true, check if batching snapshots the en...
Adi Roiban (adiroiban) wrote : | # |
On Wed, 2010-05-26 at 16:12 +0000, Данило Шеган wrote:
> Review: Needs Fixing
> Hi Adi,
>
> Ok, I realized there are more things to fix first. We've discussed them
> over on IRC, but I will repeat myself a bit for reference.
>
> review needs-fixing
>
> Attribute names should include as little gettextisms as possible:
> "all_pofiles" and "all_potemplates" should be "translation_files" and
> "translation_
> branch: I am not sure about the "all").
renamed all_pofiles to translation_files
removed all_translation
a method.
I have renamed the name used for exporting pofile and potemplate entries
and collections.
> And further on that topic, we should only show most relevant translation
> templates: these are usually only the current, non-obsolete ones.
> Obsolete templates are useful only for management purposes, and if we
> want, we can export them either separately, or export all of
>
> getCurrentTrans
> getObsoleteTran
> getTranslationT
>
> There is no need to wrap either of the methods in a property in order to
> export them. What's else, these methods expose some implementation
> details (like "just_ids" parameter, needed for performance reasons
> elsewhere) and we should not get them exported as such.
>
> Since I want to see this branch move in soon, I don't want to dwell on
> cleaning up these right now.
We can hide the "just_ids" in the exported API call.
We can export getCurrentTrans
hidden and always set to False.
I still think that exporting getTranslationT
simpler (rather than exporting all 3 methods) and the client side check
for active/inactive templates is not that complicated.
> Now, performance reasons are very important to consider here. We may
> have to investigate whether `doNotSnapshot` is needed, and how batching
> works over Collection results ([1] suggests it splits results into
> batches of 75, but we'd have to check that). If API framework splits
> the results into batches and only serializes a single batch (vs
> serializing a whole result set), it'd be ok even if we don't use
> doNotSnapshot (unless it turns out to be too slow once it hits
> edge/staging, when we'll need to fix it).
I will raise this discussion over the lp-dev ML. I still have to read
the code and see exactly why, where and how those snosphots are
needed/used in order to ask a valid question.
I think that we should land this branch and the start of next cycle.
The first attempt should be without doNotSnapshot. If something goes
wrong we can reconsider our options.
> Also, at the moment, we should export only the most useful list of
> templates (because most of this code needs slight refactoring, we should
> not export all methods and then stop exporting them soon after). At the
> moment, for the "reporting" use case, I believe only "current" templates
> make sense to be exported. Now, exporting it with just_ids parameter is
> fine as well, and we can fix it with the refactoring in the future.
See above comments.
> Next, we...
Jeroen T. Vermeulen (jtv) wrote : | # |
We've been discussing this in IRC. It turns out that IDistroSeries.
The docstring deliberately makes no promise that getTranslationT
Jeroen T. Vermeulen (jtv) wrote : | # |
Revision 10369 looks good to me (except the part where you update the getTranslationT
You can also make the check easier to read by eliminating individual, simple cases:
if official_rosetta and potemplate.
# This template is available for translation.
return potemplate
elif check_permissio
# User has special privileges for this template.
return potemplate
else:
raise NotFoundError(name)
Also, a bit higher up, I don't think the assertion for "unknown context" carries its weight. We have database constraints enforcing it. So might as well do something simpler such as:
if potemplate.
product_
else:
product_
official_rosetta = product_
Jeroen T. Vermeulen (jtv) wrote : | # |
For the record I should add that we first discussed the bigger issues (performance, security, various batching hazards) as per Danilo's proposed course of action above. All those points have been satisfied, so the nitpicking about small bits of code means that the branch is in good shape. There is no problematic snapshotting, performance is good, and with the removal of that shortlist we no longer fetch all templates in a distroseries at once.
Adi Roiban (adiroiban) wrote : | # |
Hi,
Here is the diff with the changes discussed in the latest comment.
If everything is ok, can you please sent this branch to ec2-test?
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -1886,7 +1886,7 @@
"""See `IHasTranslatio
result = POTemplate.
- return shortlist(result, 2000)
+ return result
def getCurrentTrans
"""See `IHasTranslatio
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -427,7 +427,7 @@
"""See `IHasTranslatio
result = POTemplate.
- return shortlist(result, 300)
+ return result
def getCurrentTrans
"""See `IHasTranslatio
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -602,7 +602,7 @@
result = POTemplate.
- return shortlist(
+ return result.
def getCurrentTrans
"""See `IHasTranslatio
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -774,18 +774,17 @@
# Get whether the target for the requested template is officially
# using Launchpad Translations.
- if potemplate.
- official_rosetta = potemplate.
- elif potemplate.product is not None:
- official_rosetta = potemplate.
+ if potemplate.
+ product_or_distro = potemplate.
else:
- raise AssertionError(
+ product_or_distro = potemplate.
+ official_rosetta = product_
- if ((official_rosetta and potemplate.
- check_permissio
- # The target is using officially Launchpad Translations and the
- # template is available to be translated, or the user is a is a
- # Launchpad administrator in which case we show everything.
+ if official_rosetta and potemplate.
+ # This template is av...
Preview Diff
1 | === modified file 'lib/canonical/launchpad/interfaces/_schema_circular_imports.py' |
2 | --- lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2010-05-14 08:05:23 +0000 |
3 | +++ lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2010-06-03 16:14:30 +0000 |
4 | @@ -24,6 +24,8 @@ |
5 | patch_plain_parameter_type, patch_choice_parameter_type, |
6 | patch_reference_property) |
7 | |
8 | +from canonical.launchpad.interfaces.message import ( |
9 | + IIndexedMessage, IMessage, IUserToUserEmail) |
10 | from lp.registry.interfaces.structuralsubscription import ( |
11 | IStructuralSubscription, IStructuralSubscriptionTarget) |
12 | from lp.bugs.interfaces.bug import IBug, IFrontPageBugAddForm |
13 | @@ -52,16 +54,17 @@ |
14 | ISourcePackageRecipe) |
15 | from lp.code.interfaces.sourcepackagerecipebuild import ( |
16 | ISourcePackageRecipeBuild) |
17 | +from lp.hardwaredb.interfaces.hwdb import HWBus, IHWSubmission |
18 | from lp.registry.interfaces.distribution import IDistribution |
19 | from lp.registry.interfaces.distributionmirror import IDistributionMirror |
20 | from lp.registry.interfaces.distributionsourcepackage import ( |
21 | IDistributionSourcePackage) |
22 | from lp.registry.interfaces.distroseries import IDistroSeries |
23 | from lp.registry.interfaces.person import IPerson, IPersonPublic |
24 | -from lp.hardwaredb.interfaces.hwdb import HWBus, IHWSubmission |
25 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
26 | from lp.registry.interfaces.product import IProduct |
27 | from lp.registry.interfaces.productseries import IProductSeries |
28 | +from lp.registry.interfaces.sourcepackage import ISourcePackage |
29 | from lp.soyuz.interfaces.archive import IArchive |
30 | from lp.soyuz.interfaces.archivepermission import ( |
31 | IArchivePermission) |
32 | @@ -77,9 +80,9 @@ |
33 | from lp.soyuz.interfaces.queue import ( |
34 | IPackageUpload, PackageUploadCustomFormat, PackageUploadStatus) |
35 | from lp.soyuz.interfaces.sourcepackagerelease import ISourcePackageRelease |
36 | -from lp.registry.interfaces.sourcepackage import ISourcePackage |
37 | -from canonical.launchpad.interfaces.message import ( |
38 | - IIndexedMessage, IMessage, IUserToUserEmail) |
39 | +from lp.translations.interfaces.pofile import IPOFile |
40 | +from lp.translations.interfaces.potemplate import ( |
41 | + IPOTemplate, IPOTemplateSharingSubset, IPOTemplateSubset) |
42 | |
43 | |
44 | IBranch['bug_branches'].value_type.schema = IBugBranch |
45 | @@ -394,5 +397,16 @@ |
46 | # IBugTracker |
47 | patch_reference_property(IBugTracker, 'owner', IPerson) |
48 | |
49 | +# IPOTemplate |
50 | +patch_collection_property(IPOTemplate, 'pofiles', IPOFile) |
51 | +patch_reference_property(IPOTemplate, 'product', IProduct) |
52 | + |
53 | +# IPOTemplateSubset |
54 | +patch_reference_property(IPOTemplateSubset, 'distroseries', IDistroSeries) |
55 | +patch_reference_property(IPOTemplateSubset, 'productseries', IProductSeries) |
56 | + |
57 | +# IPOTemplateSharingSubset |
58 | +patch_reference_property(IPOTemplateSharingSubset, 'product', IProduct) |
59 | + |
60 | # IProductSeries |
61 | patch_reference_property(IProductSeries, 'product', IProduct) |
62 | |
63 | === modified file 'lib/canonical/launchpad/security.py' |
64 | --- lib/canonical/launchpad/security.py 2010-05-24 04:54:44 +0000 |
65 | +++ lib/canonical/launchpad/security.py 2010-06-03 16:14:30 +0000 |
66 | @@ -61,8 +61,7 @@ |
67 | from lp.services.worlddata.interfaces.language import ILanguage, ILanguageSet |
68 | from lp.translations.interfaces.languagepack import ILanguagePack |
69 | from canonical.launchpad.interfaces.launchpad import ( |
70 | - IBazaarApplication, IHasBug, IHasDrivers, ILaunchpadCelebrities, |
71 | - IPersonRoles) |
72 | + IHasBug, IHasDrivers, ILaunchpadCelebrities, IPersonRoles) |
73 | from lp.registry.interfaces.role import IHasOwner |
74 | from lp.registry.interfaces.location import IPersonLocation |
75 | from lp.registry.interfaces.mailinglist import IMailingListSet |
76 | @@ -1159,6 +1158,11 @@ |
77 | self.obj).checkAuthenticated(user)) |
78 | |
79 | |
80 | +class ViewPOTemplates(AnonymousAuthorization): |
81 | + """Anyone can view an IPOTemplate.""" |
82 | + usedfor = IPOTemplate |
83 | + |
84 | + |
85 | class AdminPOTemplateDetails(OnlyRosettaExpertsAndAdmins): |
86 | """Controls administration of an `IPOTemplate`. |
87 | |
88 | @@ -1211,6 +1215,11 @@ |
89 | usedfor = IProductSeries |
90 | |
91 | |
92 | +class ViewPOFile(AnonymousAuthorization): |
93 | + """Anyone can view an IPOFile.""" |
94 | + usedfor = IPOFile |
95 | + |
96 | + |
97 | class EditPOFileDetails(EditByOwnersOrAdmins): |
98 | usedfor = IPOFile |
99 | |
100 | |
101 | === modified file 'lib/lp/registry/configure.zcml' |
102 | --- lib/lp/registry/configure.zcml 2010-04-27 13:57:18 +0000 |
103 | +++ lib/lp/registry/configure.zcml 2010-06-03 16:14:30 +0000 |
104 | @@ -113,8 +113,6 @@ |
105 | <allow |
106 | interface="lp.translations.interfaces.translationimportqueue.IHasTranslationImports"/> |
107 | <allow |
108 | - interface="lp.translations.interfaces.potemplate.IHasTranslationTemplates"/> |
109 | - <allow |
110 | interface="canonical.launchpad.interfaces.ICanPublishPackages"/> |
111 | <require |
112 | permission="launchpad.Edit" |
113 | @@ -1325,8 +1323,6 @@ |
114 | interface="lp.bugs.interfaces.bugtarget.IHasBugHeat"/> |
115 | <allow |
116 | interface="lp.translations.interfaces.translationimportqueue.IHasTranslationImports"/> |
117 | - <allow |
118 | - interface="lp.translations.interfaces.potemplate.IHasTranslationTemplates"/> |
119 | <require |
120 | permission="launchpad.Edit" |
121 | set_attributes="product name owner driver summary branch |
122 | @@ -1529,8 +1525,6 @@ |
123 | interface="canonical.launchpad.interfaces.IHasBuildRecords"/> |
124 | <allow |
125 | interface="lp.translations.interfaces.translationimportqueue.IHasTranslationImports"/> |
126 | - <allow |
127 | - interface="lp.translations.interfaces.potemplate.IHasTranslationTemplates"/> |
128 | |
129 | <!-- IQuestionTarget --> |
130 | |
131 | |
132 | === modified file 'lib/lp/registry/interfaces/distroseries.py' |
133 | --- lib/lp/registry/interfaces/distroseries.py 2010-04-27 22:22:20 +0000 |
134 | +++ lib/lp/registry/interfaces/distroseries.py 2010-06-03 16:14:30 +0000 |
135 | @@ -51,6 +51,7 @@ |
136 | IStructuralSubscriptionTarget) |
137 | from lp.soyuz.interfaces.buildrecords import IHasBuildRecords |
138 | from lp.translations.interfaces.languagepack import ILanguagePack |
139 | +from lp.translations.interfaces.potemplate import IHasTranslationTemplates |
140 | |
141 | |
142 | class DistroSeriesNameField(ContentNameField): |
143 | @@ -113,7 +114,7 @@ |
144 | |
145 | def _validate(self, version): |
146 | """See `UniqueField`.""" |
147 | - super(DistroSeriesVersionField, self)._validate(version) |
148 | + DistroSeriesVersionField._validate(self, version) |
149 | if not sane_version(version): |
150 | raise LaunchpadValidationError( |
151 | "%s is not a valid version" % version) |
152 | @@ -142,7 +143,7 @@ |
153 | class IDistroSeriesPublic( |
154 | ISeriesMixin, IHasAppointedDriver, IHasOwner, IBugTarget, |
155 | ISpecificationGoal, IHasMilestones, IHasOfficialBugTags, |
156 | - IHasBuildRecords): |
157 | + IHasBuildRecords, IHasTranslationTemplates): |
158 | """Public IDistroSeries properties.""" |
159 | |
160 | id = Attribute("The distroseries's unique number.") |
161 | @@ -593,7 +594,8 @@ |
162 | :param dsc: string, original content of the dsc file |
163 | :param copyright: string, the original debian/copyright content |
164 | :param changelog: LFA ID of the debian/changelog file in librarian |
165 | - :param changelog_entry: string, changelog extracted from the changesfile |
166 | + :param changelog_entry: string, changelog extracted from the |
167 | + changesfile |
168 | :param architecturehintlist: string, DSC architectures |
169 | :param builddepends: string, DSC build dependencies |
170 | :param builddependsindep: string, DSC architecture independent build |
171 | |
172 | === modified file 'lib/lp/registry/interfaces/productseries.py' |
173 | --- lib/lp/registry/interfaces/productseries.py 2010-03-25 20:36:46 +0000 |
174 | +++ lib/lp/registry/interfaces/productseries.py 2010-06-03 16:14:30 +0000 |
175 | @@ -32,6 +32,7 @@ |
176 | from lp.registry.interfaces.productrelease import IProductRelease |
177 | from lp.blueprints.interfaces.specificationtarget import ( |
178 | ISpecificationGoal) |
179 | +from lp.translations.interfaces.potemplate import IHasTranslationTemplates |
180 | from lp.translations.interfaces.translations import ( |
181 | TranslationsBranchImportMode) |
182 | from canonical.launchpad.interfaces.validation import validate_url |
183 | @@ -91,7 +92,8 @@ |
184 | |
185 | class IProductSeriesPublic( |
186 | ISeriesMixin, IHasAppointedDriver, IHasOwner, IBugTarget, |
187 | - ISpecificationGoal, IHasMilestones, IHasOfficialBugTags): |
188 | + ISpecificationGoal, IHasMilestones, IHasOfficialBugTags, |
189 | + IHasTranslationTemplates): |
190 | """Public IProductSeries properties.""" |
191 | # XXX Mark Shuttleworth 2004-10-14: Would like to get rid of id in |
192 | # interfaces, as soon as SQLobject allows using the object directly |
193 | |
194 | === modified file 'lib/lp/registry/interfaces/sourcepackage.py' |
195 | --- lib/lp/registry/interfaces/sourcepackage.py 2010-04-01 20:26:16 +0000 |
196 | +++ lib/lp/registry/interfaces/sourcepackage.py 2010-06-03 16:14:30 +0000 |
197 | @@ -19,21 +19,23 @@ |
198 | from zope.interface import Attribute, Interface |
199 | from zope.schema import Choice, Object, TextLine |
200 | from lazr.enum import DBEnumeratedType, DBItem |
201 | +from lazr.restful.fields import Reference, ReferenceChoice |
202 | +from lazr.restful.declarations import ( |
203 | + call_with, export_as_webservice_entry, export_read_operation, |
204 | + export_write_operation, exported, operation_parameters, |
205 | + operation_returns_entry, REQUEST_USER) |
206 | |
207 | from canonical.launchpad import _ |
208 | from lp.bugs.interfaces.bugtarget import IBugTarget, IHasOfficialBugTags |
209 | from lp.code.interfaces.hasbranches import ( |
210 | IHasBranches, IHasCodeImports, IHasMergeProposals) |
211 | from lp.soyuz.interfaces.component import IComponent |
212 | -from lazr.restful.fields import Reference, ReferenceChoice |
213 | -from lazr.restful.declarations import ( |
214 | - call_with, export_as_webservice_entry, export_read_operation, |
215 | - export_write_operation, exported, operation_parameters, |
216 | - operation_returns_entry, REQUEST_USER) |
217 | +from lp.translations.interfaces.potemplate import IHasTranslationTemplates |
218 | |
219 | |
220 | class ISourcePackage(IBugTarget, IHasBranches, IHasMergeProposals, |
221 | - IHasOfficialBugTags, IHasCodeImports): |
222 | + IHasOfficialBugTags, IHasCodeImports, |
223 | + IHasTranslationTemplates): |
224 | """A SourcePackage. See the MagicSourcePackage specification. This |
225 | interface preserves as much as possible of the old SourcePackage |
226 | interface from the SourcePackage table, with the new table-less |
227 | |
228 | === modified file 'lib/lp/registry/model/distroseries.py' |
229 | --- lib/lp/registry/model/distroseries.py 2010-05-12 23:23:19 +0000 |
230 | +++ lib/lp/registry/model/distroseries.py 2010-06-03 16:14:30 +0000 |
231 | @@ -103,7 +103,6 @@ |
232 | from lp.translations.interfaces.languagepack import LanguagePackType |
233 | from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet |
234 | from lp.soyuz.interfaces.queue import PackageUploadStatus |
235 | -from lp.translations.interfaces.potemplate import IHasTranslationTemplates |
236 | from lp.soyuz.interfaces.publishedpackage import ( |
237 | IPublishedPackageSet) |
238 | from lp.soyuz.interfaces.publishing import ( |
239 | @@ -131,7 +130,7 @@ |
240 | """A particular series of a distribution.""" |
241 | implements( |
242 | ICanPublishPackages, IDistroSeries, IHasBugHeat, IHasBuildRecords, |
243 | - IHasQueueItems, IHasTranslationTemplates) |
244 | + IHasQueueItems) |
245 | |
246 | _table = 'DistroSeries' |
247 | _defaultOrder = ['distribution', 'version'] |
248 | @@ -1303,15 +1302,13 @@ |
249 | find_spec = ( |
250 | DistroSeriesPackageCache, |
251 | BinaryPackageName, |
252 | - SQL('rank(fti, ftq(%s)) AS rank' % sqlvalues(text)) |
253 | - ) |
254 | + SQL('rank(fti, ftq(%s)) AS rank' % sqlvalues(text))) |
255 | origin = [ |
256 | DistroSeriesPackageCache, |
257 | Join( |
258 | BinaryPackageName, |
259 | DistroSeriesPackageCache.binarypackagename == |
260 | - BinaryPackageName.id |
261 | - ) |
262 | + BinaryPackageName.id), |
263 | ] |
264 | |
265 | # Note: When attempting to convert the query below into straight |
266 | @@ -1325,7 +1322,7 @@ |
267 | DistroSeriesPackageCache.name ILIKE '%%' || %s || '%%') |
268 | """ % (quote(self), |
269 | quote(self.distribution.all_distro_archive_ids), |
270 | - quote(text), quote_like(text)) |
271 | + quote(text), quote_like(text)), |
272 | ).config(distinct=True) |
273 | |
274 | # Create a function that will decorate the results, converting |
275 | @@ -1889,7 +1886,7 @@ |
276 | """See `IHasTranslationTemplates`.""" |
277 | result = POTemplate.selectBy(distroseries=self, |
278 | orderBy=['-priority', 'name']) |
279 | - return shortlist(result, 2000) |
280 | + return result |
281 | |
282 | def getCurrentTranslationTemplates(self, just_ids=False): |
283 | """See `IHasTranslationTemplates`.""" |
284 | |
285 | === modified file 'lib/lp/registry/model/productseries.py' |
286 | --- lib/lp/registry/model/productseries.py 2010-03-24 02:53:42 +0000 |
287 | +++ lib/lp/registry/model/productseries.py 2010-06-03 16:14:30 +0000 |
288 | @@ -53,7 +53,6 @@ |
289 | from canonical.launchpad.helpers import shortlist |
290 | from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities |
291 | from lp.registry.interfaces.packaging import PackagingType |
292 | -from lp.translations.interfaces.potemplate import IHasTranslationTemplates |
293 | from lp.blueprints.interfaces.specification import ( |
294 | SpecificationDefinitionStatus, SpecificationFilter, |
295 | SpecificationGoalStatus, SpecificationImplementationStatus, |
296 | @@ -84,7 +83,7 @@ |
297 | HasTranslationImportsMixin, HasTranslationTemplatesMixin, |
298 | StructuralSubscriptionTargetMixin, SeriesMixin): |
299 | """A series of product releases.""" |
300 | - implements(IHasBugHeat, IProductSeries, IHasTranslationTemplates) |
301 | + implements(IHasBugHeat, IProductSeries) |
302 | |
303 | _table = 'ProductSeries' |
304 | |
305 | @@ -428,7 +427,7 @@ |
306 | """See `IHasTranslationTemplates`.""" |
307 | result = POTemplate.selectBy( |
308 | productseries=self, orderBy=['-priority', 'name']) |
309 | - return shortlist(result, 300) |
310 | + return result |
311 | |
312 | def getCurrentTranslationTemplates(self, just_ids=False): |
313 | """See `IHasTranslationTemplates`.""" |
314 | @@ -614,4 +613,3 @@ |
315 | import_mode != TranslationsBranchImportMode.NO_IMPORT) |
316 | |
317 | return Store.of(branch).find(ProductSeries, And(*conditions)) |
318 | - |
319 | |
320 | === modified file 'lib/lp/registry/model/sourcepackage.py' |
321 | --- lib/lp/registry/model/sourcepackage.py 2010-04-14 18:31:51 +0000 |
322 | +++ lib/lp/registry/model/sourcepackage.py 2010-06-03 16:14:30 +0000 |
323 | @@ -54,7 +54,6 @@ |
324 | from canonical.launchpad.helpers import shortlist |
325 | from lp.soyuz.interfaces.buildrecords import IHasBuildRecords |
326 | from lp.registry.interfaces.packaging import PackagingType |
327 | -from lp.translations.interfaces.potemplate import IHasTranslationTemplates |
328 | from lp.registry.interfaces.distribution import NoPartnerArchive |
329 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
330 | from lp.soyuz.interfaces.publishing import PackagePublishingStatus |
331 | @@ -170,8 +169,7 @@ |
332 | """ |
333 | |
334 | implements( |
335 | - ISourcePackage, IHasBugHeat, IHasBuildRecords, |
336 | - IHasTranslationTemplates, IQuestionTarget) |
337 | + ISourcePackage, IHasBugHeat, IHasBuildRecords, IQuestionTarget) |
338 | |
339 | classProvides(ISourcePackageFactory) |
340 | |
341 | @@ -604,7 +602,7 @@ |
342 | result = POTemplate.selectBy( |
343 | distroseries=self.distroseries, |
344 | sourcepackagename=self.sourcepackagename) |
345 | - return shortlist(result.orderBy(['-priority', 'name']), 300) |
346 | + return result.orderBy(['-priority', 'name']) |
347 | |
348 | def getCurrentTranslationTemplates(self, just_ids=False): |
349 | """See `IHasTranslationTemplates`.""" |
350 | |
351 | === modified file 'lib/lp/registry/stories/webservice/xx-distroseries.txt' |
352 | --- lib/lp/registry/stories/webservice/xx-distroseries.txt 2010-03-06 01:24:05 +0000 |
353 | +++ lib/lp/registry/stories/webservice/xx-distroseries.txt 2010-06-03 16:14:30 +0000 |
354 | @@ -1,4 +1,5 @@ |
355 | -= Distribution Series = |
356 | +Distribution Series |
357 | +=================== |
358 | |
359 | We can get a distroseries object via a distribution object in several ways: |
360 | |
361 | |
362 | === modified file 'lib/lp/registry/stories/webservice/xx-project-registry.txt' |
363 | --- lib/lp/registry/stories/webservice/xx-project-registry.txt 2010-05-07 18:18:56 +0000 |
364 | +++ lib/lp/registry/stories/webservice/xx-project-registry.txt 2010-06-03 16:14:30 +0000 |
365 | @@ -858,8 +858,10 @@ |
366 | >>> babadoo_foobadoo = webservice.get('/babadoo/foobadoo').jsonBody() |
367 | >>> pprint_entry(babadoo_foobadoo) |
368 | active: True |
369 | - active_milestones_collection_link: u'http://.../babadoo/foobadoo/active_milestones' |
370 | - all_milestones_collection_link: u'http://.../babadoo/foobadoo/all_milestones' |
371 | + active_milestones_collection_link: |
372 | + u'http://.../babadoo/foobadoo/active_milestones' |
373 | + all_milestones_collection_link: |
374 | + u'http://.../babadoo/foobadoo/all_milestones' |
375 | branch_link: u'http://.../~babadoo-owner/babadoo/fooey' |
376 | bug_reporting_guidelines: None |
377 | date_created: u'...' |
378 | @@ -1088,12 +1090,15 @@ |
379 | >>> pprint_entry(result) |
380 | date_uploaded: u'2005-06-06T08:59:51.926792+00:00' |
381 | description: None |
382 | - file_link: u'http://.../firefox/trunk/0.9.2/+file/firefox_0.9.2.orig.tar.gz/file' |
383 | + file_link: |
384 | + u'http://.../firefox/trunk/0.9.2/+file/firefox_0.9.2.orig.tar.gz/file' |
385 | file_type: u'Code Release Tarball' |
386 | project_release_link: u'http://.../firefox/trunk/0.9.2' |
387 | resource_type_link: u'http://.../#project_release_file' |
388 | - self_link: u'http://.../firefox/trunk/0.9.2/+file/firefox_0.9.2.orig.tar.gz' |
389 | - signature_link: u'http://.../firefox/trunk/0.9.2/+file/firefox_0.9.2.orig.tar.gz/signature' |
390 | + self_link: |
391 | + u'http://.../firefox/trunk/0.9.2/+file/firefox_0.9.2.orig.tar.gz' |
392 | + signature_link: |
393 | + u'http://.../trunk/0.9.2/+file/firefox_0.9.2.orig.tar.gz/signature' |
394 | |
395 | The actual file redirects to the librarian when accessed. |
396 | |
397 | |
398 | === modified file 'lib/lp/translations/browser/potemplate.py' |
399 | --- lib/lp/translations/browser/potemplate.py 2010-04-22 17:07:56 +0000 |
400 | +++ lib/lp/translations/browser/potemplate.py 2010-06-03 16:14:30 +0000 |
401 | @@ -763,8 +763,8 @@ |
402 | def traverse(self, name): |
403 | """Return the IPOTemplate associated with the given name.""" |
404 | |
405 | - assert self.request.method in ['GET', 'HEAD', 'POST'], ( |
406 | - 'We only know about GET, HEAD, and POST') |
407 | + assert self.request.method in ['GET', 'HEAD', 'PATCH', 'POST'], ( |
408 | + 'We only know about GET, HEAD, PATCH and POST') |
409 | |
410 | # Get the requested potemplate. |
411 | potemplate = self.context.getPOTemplateByName(name) |
412 | @@ -774,18 +774,17 @@ |
413 | |
414 | # Get whether the target for the requested template is officially |
415 | # using Launchpad Translations. |
416 | - if potemplate.distribution is not None: |
417 | - official_rosetta = potemplate.distribution.official_rosetta |
418 | - elif potemplate.product is not None: |
419 | - official_rosetta = potemplate.product.official_rosetta |
420 | + if potemplate.distribution is None: |
421 | + product_or_distro = potemplate.productseries.product |
422 | else: |
423 | - raise AssertionError('Unknown context for %s' % potemplate.title) |
424 | + product_or_distro = potemplate.distroseries.distribution |
425 | + official_rosetta = product_or_distro.official_rosetta |
426 | |
427 | - if ((official_rosetta and potemplate.iscurrent) or |
428 | - check_permission('launchpad.Edit', potemplate)): |
429 | - # The target is using officially Launchpad Translations and the |
430 | - # template is available to be translated, or the user is a is a |
431 | - # Launchpad administrator in which case we show everything. |
432 | + if official_rosetta and potemplate.iscurrent: |
433 | + # This template is available for translation. |
434 | + return potemplate |
435 | + elif check_permission('launchpad.Edit', potemplate): |
436 | + # User has Edit privileges for this template and can access it. |
437 | return potemplate |
438 | else: |
439 | raise NotFoundError(name) |
440 | |
441 | === modified file 'lib/lp/translations/interfaces/pofile.py' |
442 | --- lib/lp/translations/interfaces/pofile.py 2010-01-08 12:39:51 +0000 |
443 | +++ lib/lp/translations/interfaces/pofile.py 2010-06-03 16:14:30 +0000 |
444 | @@ -19,6 +19,9 @@ |
445 | from zope.schema.vocabulary import ( |
446 | getVocabularyRegistry, SimpleTerm, SimpleVocabulary) |
447 | |
448 | +from lazr.restful.declarations import ( |
449 | + exported, export_as_webservice_entry) |
450 | + |
451 | from canonical.launchpad import _ |
452 | from canonical.launchpad.webapp.interfaces import ILaunchBag |
453 | from lp.registry.interfaces.person import IPerson |
454 | @@ -33,8 +36,12 @@ |
455 | class IPOFile(IRosettaStats): |
456 | """A translation file.""" |
457 | |
458 | - id = Int( |
459 | - title=_('The translation file id.'), required=True, readonly=True) |
460 | + export_as_webservice_entry( |
461 | + singular_name="translation_file", |
462 | + plural_name="translation_files") |
463 | + |
464 | + id = exported(Int( |
465 | + title=_('The translation file id.'), required=True, readonly=True)) |
466 | |
467 | potemplate = Object( |
468 | title=_('The translation file template.'), |
469 | @@ -121,8 +128,8 @@ |
470 | required=False) |
471 | |
472 | translation_messages = Attribute(_( |
473 | - 'All `ITranslationMessage` objects related to this translation file.' |
474 | - )) |
475 | + "All `ITranslationMessage` objects related to this " |
476 | + "translation file.")) |
477 | |
478 | plural_forms = Int( |
479 | title=_('Number of plural forms for the language of this PO file.'), |
480 | @@ -273,7 +280,7 @@ |
481 | |
482 | def getTranslationRows(): |
483 | """Return exportable rows of translation data. |
484 | - |
485 | + |
486 | :return: a list of `VPOExport` objects. |
487 | """ |
488 | |
489 | |
490 | === modified file 'lib/lp/translations/interfaces/potemplate.py' |
491 | --- lib/lp/translations/interfaces/potemplate.py 2009-11-27 12:50:16 +0000 |
492 | +++ lib/lp/translations/interfaces/potemplate.py 2010-06-03 16:14:30 +0000 |
493 | @@ -7,13 +7,15 @@ |
494 | from zope.schema import ( |
495 | Bool, Bytes, Choice, Datetime, Int, Object, Text, TextLine) |
496 | from lazr.enum import DBEnumeratedType, DBItem |
497 | +from lazr.restful.fields import CollectionField, Reference |
498 | +from lazr.restful.declarations import ( |
499 | + exported, export_as_webservice_entry, export_read_operation, |
500 | + operation_returns_collection_of) |
501 | |
502 | +from canonical.launchpad.fields import ParticipatingPersonChoice |
503 | from canonical.launchpad.interfaces.launchpad import NotFoundError |
504 | from canonical.launchpad.interfaces.librarian import ILibraryFileAlias |
505 | from lp.registry.interfaces.distribution import IDistribution |
506 | -from lp.registry.interfaces.distroseries import IDistroSeries |
507 | -from lp.registry.interfaces.product import IProduct |
508 | -from lp.registry.interfaces.productseries import IProductSeries |
509 | from lp.translations.interfaces.rosettastats import IRosettaStats |
510 | from lp.registry.interfaces.sourcepackagename import ( |
511 | ISourcePackageName) |
512 | @@ -74,95 +76,55 @@ |
513 | search or complete listing is requested by the user. """) |
514 | |
515 | |
516 | -class IHasTranslationTemplates(Interface): |
517 | - """An entity that has translation templates attached. |
518 | - |
519 | - Examples include `ISourcePackage`, `IDistroSeries`, and `IProductSeries`. |
520 | - """ |
521 | - |
522 | - has_current_translation_templates = Bool( |
523 | - title=_("Does this object have current translation templates?"), |
524 | - readonly=True) |
525 | - |
526 | - def getCurrentTranslationTemplates(just_ids=False): |
527 | - """Return an iterator over all active translation templates. |
528 | - |
529 | - A translation template is considered active when both |
530 | - `IPOTemplate`.iscurrent and parent official_rosetta flags |
531 | - are set to True. |
532 | - """ |
533 | - |
534 | - def getCurrentTranslationFiles(just_ids=False): |
535 | - """Return an iterator over all active translation files. |
536 | - |
537 | - A translation file is active if it's attached to an |
538 | - active translation template. |
539 | - """ |
540 | - |
541 | - def getObsoleteTranslationTemplates(): |
542 | - """Return an iterator over its not active translation templates. |
543 | - |
544 | - A translation template is considered not active when any of |
545 | - `IPOTemplate`.iscurrent or `IDistribution`.official_rosetta flags |
546 | - are set to False. |
547 | - """ |
548 | - |
549 | - def getTranslationTemplates(): |
550 | - """Return an iterator over all its translation templates. |
551 | - |
552 | - The returned templates are either obsolete or current. |
553 | - """ |
554 | - |
555 | - def getTranslationTemplateFormats(): |
556 | - """A list of native formats for all current translation templates. |
557 | - """ |
558 | - |
559 | - |
560 | class IPOTemplate(IRosettaStats): |
561 | """A translation template.""" |
562 | |
563 | - id = Int( |
564 | + export_as_webservice_entry( |
565 | + singular_name='translation_template', |
566 | + plural_name='translation_templates') |
567 | + |
568 | + id = exported(Int( |
569 | title=u"The translation template id.", |
570 | - required=True, readonly=True) |
571 | + required=True, readonly=True)) |
572 | |
573 | - name = TextLine( |
574 | + name = exported(TextLine( |
575 | title=_("Template name"), |
576 | description=_("The name of this PO template, for example " |
577 | "'evolution-2.2'. Each translation template has a " |
578 | "unique name in its package. It's important to get this " |
579 | "correct, because Launchpad will recommend alternative " |
580 | "translations based on the name."), |
581 | - required=True) |
582 | + required=True)) |
583 | |
584 | - translation_domain = TextLine( |
585 | + translation_domain = exported(TextLine( |
586 | title=_("Translation domain"), |
587 | description=_("The translation domain for a translation template. " |
588 | "Used with PO file format when generating MO files for inclusion " |
589 | "in language pack or MO tarball exports."), |
590 | - required=True) |
591 | + required=True)) |
592 | |
593 | - description = Text( |
594 | + description = exported(Text( |
595 | title=_("Description"), |
596 | description=_("Please provide a brief description of the content " |
597 | "of this translation template, for example, telling translators " |
598 | "if this template contains strings for end-users or other " |
599 | "developers."), |
600 | - required=False) |
601 | + required=False)) |
602 | |
603 | header = Text( |
604 | title=_('Header'), |
605 | description=_("The standard template header in its native format."), |
606 | required=True) |
607 | |
608 | - iscurrent = Bool( |
609 | + iscurrent = exported(Bool( |
610 | title=_("Accept translations?"), |
611 | description=_( |
612 | "If unchecked, people can no longer change the template's " |
613 | "translations."), |
614 | required=True, |
615 | - default=True) |
616 | + default=True), exported_as='active') |
617 | |
618 | - owner = Choice( |
619 | + owner = exported(ParticipatingPersonChoice( |
620 | title=_("Owner"), |
621 | required=True, |
622 | description=_( |
623 | @@ -170,7 +132,7 @@ |
624 | "and change it's status, and can also upload new versions " |
625 | "of the template when a new release is made or when the " |
626 | "translation strings have been changed during development."), |
627 | - vocabulary="ValidOwner") |
628 | + vocabulary="ValidOwner")) |
629 | |
630 | productseries = Choice( |
631 | title=_("Series"), |
632 | @@ -209,29 +171,29 @@ |
633 | required=False, |
634 | vocabulary="BinaryPackageName") |
635 | |
636 | - languagepack = Bool( |
637 | + languagepack = exported(Bool( |
638 | title=_("Include translations for this template in language packs?"), |
639 | description=_( |
640 | "Check this box if this template is part of a language pack so " |
641 | "its translations should be exported that way."), |
642 | required=True, |
643 | - default=False) |
644 | + default=False), exported_as='exported_in_languagepacks') |
645 | |
646 | - path = TextLine( |
647 | + path = exported(TextLine( |
648 | title=_( |
649 | "Path of the template in the source tree, including filename."), |
650 | - required=False) |
651 | + required=False)) |
652 | |
653 | source_file = Object( |
654 | title=_('Source file for this translation template'), |
655 | readonly=True, schema=ILibraryFileAlias) |
656 | |
657 | - source_file_format = Choice( |
658 | + source_file_format = exported(Choice( |
659 | title=_("File format for the source file"), |
660 | required=False, |
661 | - vocabulary=TranslationFileFormat) |
662 | + vocabulary=TranslationFileFormat), exported_as='format') |
663 | |
664 | - priority = Int( |
665 | + priority = exported(Int( |
666 | title=_('Priority'), |
667 | required=True, |
668 | default=0, |
669 | @@ -240,7 +202,7 @@ |
670 | 'there are multiple templates, and you can use this as a way ' |
671 | 'of indicating which are more important and should be ' |
672 | 'translated first. Pick any number - higher priority ' |
673 | - 'templates will generally be listed first.')) |
674 | + 'templates will generally be listed first.'))) |
675 | |
676 | datecreated = Datetime( |
677 | title=_('When this translation template was created.'), required=True, |
678 | @@ -265,8 +227,12 @@ |
679 | '''), |
680 | vocabulary='TranslationPermission') |
681 | |
682 | - pofiles = Attribute( |
683 | - _('All `IPOFile` that exist for this template.')) |
684 | + pofiles = exported( |
685 | + CollectionField( |
686 | + title=_("All translation files that exist for this template."), |
687 | + # Really IPOFile, see _schema_circular_imports.py. |
688 | + value_type=Reference(schema=Interface)), |
689 | + exported_as='translation_files') |
690 | |
691 | relatives_by_name = Attribute( |
692 | _('All `IPOTemplate` objects that have the same name asa this one.')) |
693 | @@ -287,17 +253,24 @@ |
694 | |
695 | product = Object( |
696 | title=_('The `IProduct` to which this translation template belongs.'), |
697 | - required=False, readonly=True, schema=IProduct) |
698 | + required=False, readonly=True, |
699 | + # Really IProduct, see _schema_circular_imports.py. |
700 | + schema=Interface) |
701 | |
702 | distribution = Object( |
703 | title=_( |
704 | - 'The `IDistribution` to which this translation template belongs.' |
705 | - ), |
706 | + 'The `IDistribution` to which this translation template ' |
707 | + 'belongs.'), |
708 | readonly=True, schema=IDistribution) |
709 | |
710 | - language_count = Int( |
711 | + messagecount = exported(Int( |
712 | + title=_('The number of translation messages for this template.'), |
713 | + required=True, readonly=True), |
714 | + exported_as='message_count') |
715 | + |
716 | + language_count = exported(Int( |
717 | title=_('The number of languages for which we have translations.'), |
718 | - required=True, readonly=True) |
719 | + required=True, readonly=True)) |
720 | |
721 | translationtarget = Attribute( |
722 | _(''' |
723 | @@ -305,9 +278,9 @@ |
724 | This will either be an `ISourcePackage` or an `IProductSeries`. |
725 | ''')) |
726 | |
727 | - date_last_updated = Datetime( |
728 | + date_last_updated = exported(Datetime( |
729 | title=_('Date for last update'), |
730 | - required=True) |
731 | + required=True)) |
732 | |
733 | uses_english_msgids = Bool( |
734 | title=_("Uses English strings as msgids"), readonly=True, |
735 | @@ -537,12 +510,14 @@ |
736 | distroseries = Object( |
737 | title=_( |
738 | 'The `IDistroSeries` associated with this subset.'), |
739 | - schema=IDistroSeries) |
740 | + # Really IDistroSeries, see _schema_circular_imports.py. |
741 | + schema=Interface) |
742 | |
743 | productseries = Object( |
744 | title=_( |
745 | 'The `IProductSeries` associated with this subset.'), |
746 | - schema=IProductSeries) |
747 | + # Really IProductSeries, see _schema_circular_imports.py. |
748 | + schema=Interface) |
749 | |
750 | iscurrent = Bool( |
751 | title=_("Filter for iscurrent flag."), |
752 | @@ -599,9 +574,9 @@ |
753 | def getClosestPOTemplate(path): |
754 | """Return a `IPOTemplate` with a path closer to given path, or None. |
755 | |
756 | - If there is no `IPOTemplate` with a common path with the given argument, |
757 | - or if there are more than one `IPOTemplate` with the same common path, |
758 | - and both are the closer ones, returns None. |
759 | + If there is no `IPOTemplate` with a common path with the given, |
760 | + argument or if there are more than one `IPOTemplate` with the same |
761 | + common path, and both are the closer ones, returns None. |
762 | """ |
763 | |
764 | def findUniquePathlessMatch(filename): |
765 | @@ -677,7 +652,8 @@ |
766 | product = Object( |
767 | title=_( |
768 | 'The `IProduct` associated with this subset.'), |
769 | - schema=IProduct) |
770 | + # Really IProduct, see _schema_circular_imports.py. |
771 | + schema=Interface) |
772 | |
773 | sourcepackagename = Object( |
774 | title=_( |
775 | @@ -722,3 +698,52 @@ |
776 | content = Bytes( |
777 | title=_("PO Template File to Import"), |
778 | required=True) |
779 | + |
780 | + |
781 | +class IHasTranslationTemplates(Interface): |
782 | + """An entity that has translation templates attached. |
783 | + |
784 | + Examples include `ISourcePackage`, `IDistroSeries`, and `IProductSeries`. |
785 | + """ |
786 | + |
787 | + has_current_translation_templates = Bool( |
788 | + title=_("Does this object have current translation templates?"), |
789 | + readonly=True) |
790 | + |
791 | + def getCurrentTranslationTemplates(just_ids=False): |
792 | + """Return an iterator over all active translation templates. |
793 | + |
794 | + A translation template is considered active when both |
795 | + `IPOTemplate`.iscurrent and parent official_rosetta flags |
796 | + are set to True. |
797 | + """ |
798 | + |
799 | + def getCurrentTranslationFiles(just_ids=False): |
800 | + """Return an iterator over all active translation files. |
801 | + |
802 | + A translation file is active if it's attached to an |
803 | + active translation template. |
804 | + """ |
805 | + |
806 | + def getObsoleteTranslationTemplates(): |
807 | + """Return an iterator over its not active translation templates. |
808 | + |
809 | + A translation template is considered not active when any of |
810 | + `IPOTemplate`.iscurrent or `IDistribution`.official_rosetta flags |
811 | + are set to False. |
812 | + """ |
813 | + |
814 | + @export_read_operation() |
815 | + @operation_returns_collection_of(IPOTemplate) |
816 | + def getTranslationTemplates(): |
817 | + """Return an iterator over all its translation templates. |
818 | + |
819 | + The returned templates are either obsolete or current. |
820 | + """ |
821 | + |
822 | + def getTranslationTemplateFormats(): |
823 | + """A list of native formats for all current translation templates. |
824 | + """ |
825 | + |
826 | +# Monkey patch for circular import avoidance done in |
827 | +# _schema_circular_imports.py |
828 | |
829 | === modified file 'lib/lp/translations/interfaces/webservice.py' |
830 | --- lib/lp/translations/interfaces/webservice.py 2009-07-17 02:25:09 +0000 |
831 | +++ lib/lp/translations/interfaces/webservice.py 2010-06-03 16:14:30 +0000 |
832 | @@ -1,9 +1,24 @@ |
833 | # Copyright 2009 Canonical Ltd. This software is licensed under the |
834 | # GNU Affero General Public License version 3 (see the file LICENSE). |
835 | |
836 | +# pylint: disable-msg=W0611 |
837 | + |
838 | """All the interfaces that are exposed through the webservice.""" |
839 | |
840 | +__all__ = [ |
841 | + 'IHasTranslationImports', |
842 | + 'IPOFile', |
843 | + 'IPOTemplate', |
844 | + 'ITranslationImportQueue', |
845 | + 'ITranslationImportQueueEntry', |
846 | + ] |
847 | + |
848 | from lp.translations.interfaces.translationimportqueue import ( |
849 | IHasTranslationImports, |
850 | ITranslationImportQueue, |
851 | ITranslationImportQueueEntry) |
852 | + |
853 | +from lp.translations.interfaces.potemplate import ( |
854 | + IPOTemplate) |
855 | +from lp.translations.interfaces.pofile import ( |
856 | + IPOFile) |
857 | |
858 | === modified file 'lib/lp/translations/model/distroseries_translations_copy.py' |
859 | --- lib/lp/translations/model/distroseries_translations_copy.py 2009-07-17 00:26:05 +0000 |
860 | +++ lib/lp/translations/model/distroseries_translations_copy.py 2010-06-03 16:14:30 +0000 |
861 | @@ -44,7 +44,7 @@ |
862 | copier = MultiTableCopy(full_name, translation_tables, logger=logger) |
863 | |
864 | # Incremental copy of updates is no longer supported |
865 | - assert len(child.getTranslationTemplates()) == 0, ( |
866 | + assert child.getTranslationTemplates().is_empty(), ( |
867 | "The child series must not yet have any translation templates.") |
868 | |
869 | logger.info( |
870 | |
871 | === modified file 'lib/lp/translations/model/potemplate.py' |
872 | --- lib/lp/translations/model/potemplate.py 2010-01-12 21:29:03 +0000 |
873 | +++ lib/lp/translations/model/potemplate.py 2010-06-03 16:14:30 +0000 |
874 | @@ -1297,8 +1297,8 @@ |
875 | elif sourcepackagename is None: |
876 | # Multiple matches, and for a product not a package. |
877 | logging.warn( |
878 | - "Found %d templates with path '%s' for productseries %s" % ( |
879 | - len(matches), path, productseries.title)) |
880 | + "Found %d templates with path '%s' for productseries %s", |
881 | + len(matches), path, productseries.title) |
882 | return None |
883 | else: |
884 | # Multiple matches, for a distribution package. Prefer a |
885 | @@ -1316,9 +1316,9 @@ |
886 | else: |
887 | logging.warn( |
888 | "Found %d templates with path '%s' for package %s " |
889 | - "(%d matched on from_sourcepackagename)." % ( |
890 | - len(matches), path, sourcepackagename.name, |
891 | - len(preferred_matches))) |
892 | + "(%d matched on from_sourcepackagename).", |
893 | + len(matches), path, sourcepackagename.name, |
894 | + len(preferred_matches)) |
895 | return None |
896 | |
897 | @staticmethod |
898 | @@ -1510,10 +1510,6 @@ |
899 | if flag |
900 | ]) |
901 | |
902 | - # Store sequences so we can detect later whether we changed the |
903 | - # message. |
904 | - sequence = row.sequence |
905 | - |
906 | # Store the message. |
907 | messages.append(msgset) |
908 | |
909 | |
910 | === added file 'lib/lp/translations/stories/webservice/xx-potemplate.txt' |
911 | --- lib/lp/translations/stories/webservice/xx-potemplate.txt 1970-01-01 00:00:00 +0000 |
912 | +++ lib/lp/translations/stories/webservice/xx-potemplate.txt 2010-06-03 16:14:30 +0000 |
913 | @@ -0,0 +1,121 @@ |
914 | +PO Template webservices |
915 | +======================= |
916 | + |
917 | + |
918 | +Getting the attributes of a POTemplate |
919 | +-------------------------------------- |
920 | + |
921 | +Anonymous users have read access to PO templates attributes. |
922 | + |
923 | + >>> from lazr.restful.testing.webservice import pprint_entry |
924 | + >>> potemplate = anon_webservice.get( |
925 | + ... '/ubuntu/hoary/+source/pmount/+pots/pmount').jsonBody() |
926 | + >>> pprint_entry(potemplate) |
927 | + active: True |
928 | + date_last_updated: u'2005-05-06T20:09:23.775993+00:00' |
929 | + description: None |
930 | + exported_in_languagepacks: True |
931 | + format: u'PO format' |
932 | + id: 2 |
933 | + language_count: 8 |
934 | + message_count: 63 |
935 | + name: u'pmount' |
936 | + owner_link: u'http://.../~rosetta-admins' |
937 | + path: u'po/template.pot' |
938 | + priority: 0 |
939 | + resource_type_link: u'http://.../#translation_template' |
940 | + self_link: u'http://.../ubuntu/hoary/+source/pmount/+pots/pmount' |
941 | + translation_domain: u'pmount' |
942 | + translation_files_collection_link: |
943 | + u'http://.../pmount/+pots/pmount/translation_files' |
944 | + |
945 | +"translation_files" will list all POFiles associated with this template. |
946 | + |
947 | + >>> translation_files = anon_webservice.get( |
948 | + ... potemplate['translation_files_collection_link']).jsonBody() |
949 | + >>> print translation_files['total_size'] |
950 | + 9 |
951 | + >>> print(translation_files['entries'][0]['resource_type_link']) |
952 | + http://.../#translation_file |
953 | + |
954 | + |
955 | +Getting all potemplates for a distribution series |
956 | +------------------------------------------------- |
957 | + |
958 | +All templates associated to a distribution series are available from the |
959 | +'getTranslationTemplates' GET method. |
960 | + |
961 | + >>> from zope.component import getUtility |
962 | + >>> from canonical.launchpad.interfaces.launchpad import ( |
963 | + ... ILaunchpadCelebrities) |
964 | + >>> from lp.translations.interfaces.potemplate import IPOTemplateSet |
965 | + >>> login('admin@canonical.com') |
966 | + >>> hoary = getUtility(ILaunchpadCelebrities).ubuntu.getSeries('hoary') |
967 | + >>> templates = getUtility(IPOTemplateSet).getSubset(distroseries=hoary) |
968 | + >>> db_count = len(list(templates)) |
969 | + >>> logout() |
970 | + >>> all_translation_templates = anon_webservice.named_get( |
971 | + ... '/ubuntu/hoary/', 'getTranslationTemplates').jsonBody() |
972 | + >>> api_count = all_translation_templates['total_size'] |
973 | + >>> api_count == db_count |
974 | + True |
975 | + >>> print(all_translation_templates['entries'][0]['resource_type_link']) |
976 | + http://.../#translation_template |
977 | + |
978 | + |
979 | +Getting all potemplates for a product series |
980 | +-------------------------------------------- |
981 | + |
982 | +All translation templates for a product series are available using the |
983 | +'getTranslationTemplates' GET method. |
984 | + |
985 | + >>> login('admin@canonical.com') |
986 | + >>> productseries = factory.makeProductSeries() |
987 | + >>> potemplate_1 = factory.makePOTemplate(productseries=productseries) |
988 | + >>> potemplate_2 = factory.makePOTemplate(productseries=productseries) |
989 | + >>> potemplate_count = 2 |
990 | + >>> logout() |
991 | + >>> all_translation_templates = anon_webservice.named_get( |
992 | + ... '/%s/%s' % ( |
993 | + ... productseries.product.name, |
994 | + ... productseries.name), |
995 | + ... 'getTranslationTemplates' |
996 | + ... ).jsonBody() |
997 | + >>> api_count = all_translation_templates['total_size'] |
998 | + >>> api_count == potemplate_count |
999 | + True |
1000 | + >>> print(all_translation_templates['entries'][0]['resource_type_link']) |
1001 | + http://.../#translation_template |
1002 | + |
1003 | + |
1004 | +Getting all translation templates for a source package |
1005 | +------------------------------------------------------ |
1006 | + |
1007 | +All translation templates for a source package are available using the |
1008 | +'getTranslationTemplates' GET method. |
1009 | + |
1010 | + |
1011 | + >>> from zope.component import getUtility |
1012 | + >>> from canonical.launchpad.interfaces.launchpad import ( |
1013 | + ... ILaunchpadCelebrities) |
1014 | + >>> from lp.registry.interfaces.sourcepackagename import ( |
1015 | + ... ISourcePackageNameSet) |
1016 | + >>> from lp.translations.interfaces.potemplate import IPOTemplateSet |
1017 | + >>> login('admin@canonical.com') |
1018 | + >>> hoary = getUtility(ILaunchpadCelebrities).ubuntu.getSeries('hoary') |
1019 | + >>> evolution_package = getUtility(ISourcePackageNameSet)['evolution'] |
1020 | + >>> templates = getUtility( |
1021 | + ... IPOTemplateSet).getSubset( |
1022 | + ... distroseries=hoary, |
1023 | + ... sourcepackagename=evolution_package) |
1024 | + >>> db_count = len(list(templates)) |
1025 | + >>> logout() |
1026 | + >>> all_translation_templates = anon_webservice.named_get( |
1027 | + ... '/ubuntu/hoary/+source/evolution', |
1028 | + ... 'getTranslationTemplates').jsonBody() |
1029 | + >>> api_count = all_translation_templates['total_size'] |
1030 | + >>> api_count == db_count |
1031 | + True |
1032 | + >>> print(all_translation_templates['entries'][0]['resource_type_link']) |
1033 | + http://.../#translation_template |
1034 | + |
Hi Adi,
It's really great that you're doing this. I'm reading it through and it looks good to me so far. One note though about the testing in xx-distroseries .txt.
You've got the problem here that you have to rely on existing test data, which can be a bit arbitrary. For example, the fact that there are 6 templates in the distroseries is pretty meaningless in the context of the test. But it's a lot of trouble to set up a fresh distroseries with fresh translation templates, especially if the existing tests don't do it either.
So here's an idea: instead of printing the exact number of templates, why not show that int(all_ translation_ templates[ 'total_ size']) is identical to len(list( getUtility( ILaunchpadCeleb rities) .ubuntu. getSeries( 'hoary' ))).
Jeroen