> Edwin this branch looks great. I expected the multistep stuff to be much
> harder. Thanks for a nice branch and thorough explanations.
Hi Brad,
Here are some tests that were broken by +edit-packaging being two steps
now. I also have changes to browser/sourcepackage.py, since I had
erroneously edit the field's default without copying the field, so the
default value was propagated to other views and was not only a bad value
but also a stale storm object. I'm setting the default manually, since
passing in the render_context is more complicated for the multistep views.
-Edwin
Incremental diff:
=== modified file 'lib/lp/bugs/stories/bug-also-affects/xx-also-affects-upstream-default-values.txt'
--- lib/lp/bugs/stories/bug-also-affects/xx-also-affects-upstream-default-values.txt 2009-06-12 16:36:02 +0000
+++ lib/lp/bugs/stories/bug-also-affects/xx-also-affects-upstream-default-values.txt 2010-02-17 03:16:46 +0000
@@ -37,8 +37,9 @@
Let's follow the link and specify the packaging information.
+from lazr.restful.interface import copy_field
+
from canonical.widgets import LaunchpadRadioWidget
from canonical.launchpad import helpers
@@ -143,8 +145,8 @@
class SourcePackageChangeUpstreamStepOne(StepView):
"""A view to set the `IProductSeries` of a sourcepackage."""
- schema = IProductSeries
- _field_names = ['product']
+ schema = Interface
+ _field_names = []
step_name = 'sourcepackage_change_upstream_step1'
template = ViewPageTemplateFile(
@@ -158,7 +160,12 @@ super(SourcePackageChangeUpstreamStepOne, self).setUpFields()
series = self.context.productseries
if series is not None:
- self.form_fields['product'].field.default = series.product
+ default = series.product
+ else:
+ default = None
+ product_field = copy_field(
+ IProductSeries['product'], default=default)
+ self.form_fields += Fields(product_field)
@property
def cancel_url(self):
=== modified file 'lib/lp/registry/browser/tests/sourcepackage-views.txt'
--- lib/lp/registry/browser/tests/sourcepackage-views.txt 2010-02-12 14:04:16 +0000
+++ lib/lp/registry/browser/tests/sourcepackage-views.txt 2010-02-18 20:37:41 +0000
@@ -22,35 +22,67 @@
>>> print view.page_title
Link to an upstream project
-The view allows the logged in user to change product series field. The value
-of the product series field is None by default because it is not required to
-create a source package.
-
- >>> view.field_names
- ['productseries']
-
- >>> print view.widgets.get('productseries')._getFormValue()
+The view allows the logged in user to change product series field. The
+value of the product field is None by default because it is not required
+to create a source package.
+
+ # The product field is added in setUpFields().
+ >>> view.view.field_names
+ ['__visited_steps__']
+ >>> [form_field.__name__ for form_field in view.view.form_fields]
+ ['__visited_steps__', 'product']
+
+ >>> print view.view.widgets.get('product')._getFormValue()
<BLANKLINE>
>>> print package.productseries
None
+This is a multistep view. In the first step, the product is specified.
+
+ >>> print view.view.__class__.__name__
+ SourcePackageChangeUpstreamStepOne
+ >>> print view.view.request.form
+ {'field.__visited_steps__': 'sourcepackage_change_upstream_step1'}
+
>>> login_person(product.owner)
>>> form = {
- ... 'field.productseries': 'bonkers/crazy',
- ... 'field.actions.change': 'Change',
+ ... 'field.product': 'bonkers',
+ ... 'field.actions.continue': 'Continue',
... }
+ >>> form.update(view.view.request.form)
>>> view = create_initialized_view(
... package, name='+edit-packaging', form=form,
... principal=product.owner)
- >>> view.errors
+ >>> view.view.errors
[]
- >>> print view.next_url
+In the second step, one of the series of the previously selected
+product can be chosen from a list of options.
+
+ >>> print view.view.__class__.__name__
+ SourcePackageChangeUpstreamStepTwo
+ >>> print view.view.request.form['field.__visited_steps__']
+ sourcepackage_change_upstream_step1|sourcepackage_change_upstream_step2
+ >>> [term.token for term in view.view.widgets['productseries'].vocabulary]
+ ['trunk', 'crazy']
+
+ >>> form = {
+ ... 'field.__visited_steps__': 'sourcepackage_change_upstream_step2',
+ ... 'field.product': 'bonkers',
+ ... 'field.productseries': 'crazy',
+ ... 'field.actions.continue': 'continue',
+ ... }
+ >>> view = create_initialized_view(
+ ... package, name='+edit-packaging', form=form,
+ ... principal=product.owner)
+
+ >>> ignored = view.view.render()
+ >>> print view.view.next_url http://launchpad.dev/youbuntu/busy/+source/bonkers
>>> for notification in view.request.response.notifications:
@@ -62,26 +94,40 @@
>>> transaction.commit()
-The form shows the current product series if it is set.
+The form shows the current product if it is set.
>>> view = create_initialized_view(package, name='+edit-packaging')
- >>> print view.widgets.get('productseries')._getFormValue().name
+
+ >>> print view.view.widgets.get('product')._getFormValue().name
+ bonkers
+
+If the same product as the current product series is selected,
+then the current product series will be the selected option.
+
+ >>> form = {
+ ... 'field.product': 'bonkers',
+ ... 'field.actions.continue': 'Continue',
+ ... }
+ >>> form.update(view.view.request.form)
+ >>> view = create_initialized_view(
+ ... package, name='+edit-packaging', form=form,
+ ... principal=product.owner)
+ >>> print view.view.widgets.get('productseries')._getFormValue().name
crazy
-The form requires a product series. An error is raised if the field is left
+The form requires a product. An error is raised if the field is left
empty.
>>> form = {
- ... 'field.productseries': '',
- ... 'field.actions.change': 'Change',
+ ... 'field.product': '',
+ ... 'field.actions.continue': 'Continue',
... }
>>> view = create_initialized_view(
... package, name='+edit-packaging', form=form,
... principal=product.owner)
- >>> for error in view.errors:
+ >>> for error in view.view.errors:
... print error
- ('productseries', u'Project series', RequiredMissing())
- You must choose a project series.
+ ('product', u'Project', RequiredMissing())
Submitting the same product series as the current packaging is not an error,
but there is no notification message that the upstream link was updated.
@@ -93,7 +139,7 @@
>>> view = create_initialized_view(
... package, name='+edit-packaging', form=form,
... principal=product.owner)
- >>> view.errors
+ >>> view.view.errors
[]
>>> print view.request.response.notifications
=== modified file 'lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt'
--- lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt 2010-02-12 11:45:37 +0000
+++ lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt 2010-02-17 03:27:19 +0000
@@ -23,8 +23,9 @@
project. He sets the upstream packaging link and sees that it is set.
> Edwin this branch looks great. I expected the multistep stuff to be much
> harder. Thanks for a nice branch and thorough explanations.
Hi Brad,
Here are some tests that were broken by +edit-packaging being two steps sourcepackage. py, since I had
now. I also have changes to browser/
erroneously edit the field's default without copying the field, so the
default value was propagated to other views and was not only a bad value
but also a stale storm object. I'm setting the default manually, since
passing in the render_context is more complicated for the multistep views.
-Edwin
Incremental diff:
=== modified file 'lib/lp/ bugs/stories/ bug-also- affects/ xx-also- affects- upstream- default- values. txt' bugs/stories/ bug-also- affects/ xx-also- affects- upstream- default- values. txt 2009-06-12 16:36:02 +0000 bugs/stories/ bug-also- affects/ xx-also- affects- upstream- default- values. txt 2010-02-17 03:16:46 +0000
--- lib/lp/
+++ lib/lp/
@@ -37,8 +37,9 @@
Let's follow the link and specify the packaging information.
>>> user_browser. getLink( 'updating the packaging information' ).click( ) getControl( name='field. productseries' ).value = ( trunk') getControl( name='field. product' ).value = 'thunderbird' getControl( 'Continue' ).click( ) getControl( name='field. productseries' ).value = ['trunk'] getControl( 'Change' ).click( )
- >>> user_browser.
- ... 'thunderbird/
+ >>> user_browser.
+ >>> user_browser.
+ >>> user_browser.
>>> user_browser.
Now the upstream product will be chosen automatically also for pmount.
=== modified file 'lib/lp/ registry/ browser/ sourcepackage. py' registry/ browser/ sourcepackage. py 2010-02-16 18:56:38 +0000 registry/ browser/ sourcepackage. py 2010-02-18 19:27:48 +0000 vocabulary import ( aryRegistry, SimpleVocabulary, SimpleTerm)
--- lib/lp/
+++ lib/lp/
@@ -28,6 +28,8 @@
from zope.schema.
getVocabul
+from lazr.restful. interface import copy_field idget
+
from canonical.widgets import LaunchpadRadioW
from canonical.launchpad import helpers
@@ -143,8 +145,8 @@
class SourcePackageCh angeUpstreamSte pOne(StepView) :
"""A view to set the `IProductSeries` of a sourcepackage."""
- schema = IProductSeries
- _field_names = ['product']
+ schema = Interface
+ _field_names = []
step_name = 'sourcepackage_ change_ upstream_ step1' eFile(
super( SourcePackageCh angeUpstreamSte pOne, self).setUpFields() productseries fields[ 'product' ].field. default = series.product 'product' ], default=default) product_ field)
template = ViewPageTemplat
@@ -158,7 +160,12 @@
series = self.context.
if series is not None:
- self.form_
+ default = series.product
+ else:
+ default = None
+ product_field = copy_field(
+ IProductSeries[
+ self.form_fields += Fields(
@property
def cancel_url(self):
=== modified file 'lib/lp/ registry/ browser/ tests/sourcepac kage-views. txt' registry/ browser/ tests/sourcepac kage-views. txt 2010-02-12 14:04:16 +0000 registry/ browser/ tests/sourcepac kage-views. txt 2010-02-18 20:37:41 +0000
--- lib/lp/
+++ lib/lp/
@@ -22,35 +22,67 @@
>>> print view.page_title
Link to an upstream project
- >>> print view.cancel_url cancel_ url launchpad. dev/youbuntu/ busy/+source/ bonkers
+ >>> print view.view.
http://
-The view allows the logged in user to change product series field. The value get('productser ies')._ getFormValue( ) field_names steps__ '] __name_ _ for form_field in view.view. form_fields] steps__ ', 'product'] widgets. get('product' )._getFormValue ()
-of the product series field is None by default because it is not required to
-create a source package.
-
- >>> view.field_names
- ['productseries']
-
- >>> print view.widgets.
+The view allows the logged in user to change product series field. The
+value of the product field is None by default because it is not required
+to create a source package.
+
+ # The product field is added in setUpFields().
+ >>> view.view.
+ ['__visited_
+ >>> [form_field.
+ ['__visited_
+
+ >>> print view.view.
<BLANKLINE>
>>> print package. productseries
None
+This is a multistep view. In the first step, the product is specified. __class_ _.__name_ _ angeUpstreamSte pOne request. form __visited_ steps__ ': 'sourcepackage_ change_ upstream_ step1'} product. owner) productseries' : 'bonkers/crazy', actions. change' : 'Change', actions. continue' : 'Continue', view.view. request. form) initialized_ view( edit-packaging' , form=form, product. owner)
+
+ >>> print view.view.
+ SourcePackageCh
+ >>> print view.view.
+ {'field.
+
>>> login_person(
>>> form = {
- ... 'field.
- ... 'field.
+ ... 'field.product': 'bonkers',
+ ... 'field.
... }
+ >>> form.update(
>>> view = create_
... package, name='+
... principal=
- >>> view.errors
+ >>> view.view.errors
[]
- >>> print view.next_url __class_ _.__name_ _ angeUpstreamSte pTwo request. form['field. __visited_ steps__ '] change_ upstream_ step1|sourcepac kage_change_ upstream_ step2 widgets[ 'productseries' ].vocabulary] __visited_ steps__ ': 'sourcepackage_ change_ upstream_ step2', productseries' : 'crazy', actions. continue' : 'continue', initialized_ view( edit-packaging' , form=form, product. owner) launchpad. dev/youbuntu/ busy/+source/ bonkers
+In the second step, one of the series of the previously selected
+product can be chosen from a list of options.
+
+ >>> print view.view.
+ SourcePackageCh
+ >>> print view.view.
+ sourcepackage_
+ >>> [term.token for term in view.view.
+ ['trunk', 'crazy']
+
+ >>> form = {
+ ... 'field.
+ ... 'field.product': 'bonkers',
+ ... 'field.
+ ... 'field.
+ ... }
+ >>> view = create_
+ ... package, name='+
+ ... principal=
+
+ >>> ignored = view.view.render()
+ >>> print view.view.next_url
http://
>>> for notification in view.request. response. notifications:
@@ -62,26 +94,40 @@
>>> transaction. commit( )
-The form shows the current product series if it is set.
+The form shows the current product if it is set.
>>> view = create_ initialized_ view(package, name='+ edit-packaging' ) get('productser ies')._ getFormValue( ).name widgets. get('product' )._getFormValue ().name actions. continue' : 'Continue', view.view. request. form) initialized_ view( edit-packaging' , form=form, product. owner) widgets. get('productser ies')._ getFormValue( ).name
- >>> print view.widgets.
+
+ >>> print view.view.
+ bonkers
+
+If the same product as the current product series is selected,
+then the current product series will be the selected option.
+
+ >>> form = {
+ ... 'field.product': 'bonkers',
+ ... 'field.
+ ... }
+ >>> form.update(
+ >>> view = create_
+ ... package, name='+
+ ... principal=
+ >>> print view.view.
crazy
-The form requires a product series. An error is raised if the field is left
+The form requires a product. An error is raised if the field is left
empty.
>>> form = { productseries' : '', actions. change' : 'Change', actions. continue' : 'Continue', initialized_ view( edit-packaging' , form=form, product. owner)
- ... 'field.
- ... 'field.
+ ... 'field.product': '',
+ ... 'field.
... }
>>> view = create_
... package, name='+
... principal=
- >>> for error in view.errors:
+ >>> for error in view.view.errors:
... print error
- ('productseries', u'Project series', RequiredMissing())
- You must choose a project series.
+ ('product', u'Project', RequiredMissing())
Submitting the same product series as the current packaging is not an error, initialized_ view( edit-packaging' , form=form, product. owner)
but there is no notification message that the upstream link was updated.
@@ -93,7 +139,7 @@
>>> view = create_
... package, name='+
... principal=
- >>> view.errors
+ >>> view.view.errors
[]
>>> print view.request. response. notifications
=== modified file 'lib/lp/ registry/ stories/ packaging/ xx-sourcepackag e-packaging. txt' registry/ stories/ packaging/ xx-sourcepackag e-packaging. txt 2010-02-12 11:45:37 +0000 registry/ stories/ packaging/ xx-sourcepackag e-packaging. txt 2010-02-17 03:27:19 +0000
--- lib/lp/
+++ lib/lp/
@@ -23,8 +23,9 @@
project. He sets the upstream packaging link and sees that it is set.
>>> user_browser. getLink( 'Set upstream link').click() getControl( productseries" ).value = 'thunderbird/trunk' getControl( name='field. product' ).value = 'thunderbird' getControl( 'Continue' ).click( ) getControl( name='field. productseries' ).value = ['trunk'] getControl( "Change" ).click( ) text(find_ tag_by_ id( contents, 'upstreams'))
- >>> user_browser.
- ... name="field.
+ >>> user_browser.
+ >>> user_browser.
+ >>> user_browser.
>>> user_browser.
>>> print extract_
... user_browser.