← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~cjwatson/launchpad/product-project-display-name into lp:launchpad

 

Colin Watson has proposed merging lp:~cjwatson/launchpad/product-project-display-name into lp:launchpad.

Commit message:
Rename {Product,ProjectGroup}.displayname to display_name, leaving properties behind for compatibility.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/product-project-display-name/+merge/273112

Rename {Product,ProjectGroup}.displayname to display_name, leaving properties behind for compatibility.

This follows https://code.launchpad.net/~cjwatson/launchpad/person-display-name/+merge/273040.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/product-project-display-name into lp:launchpad.
=== modified file 'lib/lp/app/doc/lazr-js-widgets.txt'
--- lib/lp/app/doc/lazr-js-widgets.txt	2015-06-27 04:10:49 +0000
+++ lib/lp/app/doc/lazr-js-widgets.txt	2015-10-01 17:39:00 +0000
@@ -26,7 +26,7 @@
     >>> from lp.registry.interfaces.product import IProduct
     >>> product = factory.makeProduct(
     ...     name='widget', displayname='Widgets > important')
-    >>> title_field = IProduct['displayname']
+    >>> title_field = IProduct['display_name']
     >>> title = 'Edit the title'
     >>> widget = TextLineEditorWidget(
     ...     product, title_field, title, 'h1', max_width='90%',
@@ -36,7 +36,7 @@
 content.
 
     >>> print widget()
-    <h1 id="edit-displayname">
+    <h1 id="edit-display_name">
     <span style="max-width: 90%;"
           class="yui3-editable_text-text ellipsis">
         Widgets &gt; important
@@ -49,7 +49,7 @@
 
     >>> ignored = login_person(product.owner)
     >>> print widget()
-    <h1 id="edit-displayname">
+    <h1 id="edit-display_name">
     <span style="max-width: 90%;"
           class="yui3-editable_text-text ellipsis">
         Widgets &gt; important

=== modified file 'lib/lp/bugs/browser/bugalsoaffects.py'
--- lib/lp/bugs/browser/bugalsoaffects.py	2015-09-28 17:38:45 +0000
+++ lib/lp/bugs/browser/bugalsoaffects.py	2015-10-01 17:39:00 +0000
@@ -751,7 +751,7 @@
     @property
     def field_names(self):
         """The fields needed to choose an existing project."""
-        names = ['bug_url', 'displayname', 'name', 'summary']
+        names = ['bug_url', 'display_name', 'name', 'summary']
         if self.can_link_package:
             names.append('add_packaging')
         return names
@@ -859,7 +859,7 @@
         product = getUtility(IProductSet).createProduct(
             owner=self.user,
             name=data['name'],
-            displayname=data['displayname'], title=data['displayname'],
+            display_name=data['display_name'], title=data['display_name'],
             summary=data['summary'], licenses=self.licenses,
             registrant=self.user)
         data['product'] = product

=== modified file 'lib/lp/bugs/browser/tests/bugtask-adding-views.txt'
--- lib/lp/bugs/browser/tests/bugtask-adding-views.txt	2013-07-12 06:14:22 +0000
+++ lib/lp/bugs/browser/tests/bugtask-adding-views.txt	2015-10-01 17:39:00 +0000
@@ -464,7 +464,7 @@
     ...     'field.actions.continue': '1',
     ...     'field.bug_url': 'http://bugs.foo.org/bugs/show_bug.cgi?id=8',
     ...     'field.name': 'foo-product',
-    ...     'field.displayname': 'The Foo Product',
+    ...     'field.display_name': 'The Foo Product',
     ...     'field.summary': 'The Foo Product'}
     >>> add_task_view = create_view(
     ...     firefox_task, '+affects-new-product', form=form, method='POST')
@@ -497,7 +497,7 @@
 
     >>> flush_database_updates()
     >>> form['field.name'] = 'bar-product'
-    >>> form['field.displayname'] = 'The Bar'
+    >>> form['field.display_name'] = 'The Bar'
     >>> form['field.summary'] = 'The Bar'
     >>> add_task_view = create_view(
     ...     firefox_task, '+affects-new-product', form=form, method='POST')
@@ -519,7 +519,7 @@
     >>> flush_database_updates()
     >>> dummy = form.pop('create_new')
     >>> form['field.name'] = u'foo'
-    >>> form['field.displayname'] = 'Foo, the return'
+    >>> form['field.display_name'] = 'Foo, the return'
     >>> form['field.summary'] = 'Foo'
     >>> add_task_view = create_view(
     ...     firefox_task, '+affects-new-product', form=form, method='POST')

=== modified file 'lib/lp/bugs/browser/tests/test_bugsupervisor.py'
--- lib/lp/bugs/browser/tests/test_bugsupervisor.py	2012-08-16 05:18:54 +0000
+++ lib/lp/bugs/browser/tests/test_bugsupervisor.py	2015-10-01 17:39:00 +0000
@@ -45,7 +45,7 @@
             }
 
     def test_view_attributes(self):
-        self.product.displayname = 'Boing'
+        self.product.display_name = 'Boing'
         view = create_initialized_view(
             self.product, name='+bugsupervisor')
         label = 'Edit bug supervisor for Boing'

=== modified file 'lib/lp/bugs/browser/tests/test_bugtask_adding.py'
--- lib/lp/bugs/browser/tests/test_bugtask_adding.py	2012-01-03 00:28:55 +0000
+++ lib/lp/bugs/browser/tests/test_bugtask_adding.py	2015-10-01 17:39:00 +0000
@@ -124,7 +124,7 @@
         view = create_initialized_view(
             self.bug_task, '+affects-new-product')
         self.assertEqual(
-            ['bug_url', 'displayname', 'name', 'summary', 'add_packaging'],
+            ['bug_url', 'display_name', 'name', 'summary', 'add_packaging'],
             view.field_names)
 
     def test_register_product_fields_packaging_does_not_exist(self):
@@ -136,7 +136,7 @@
         view = create_initialized_view(
             self.bug_task, '+affects-new-product')
         self.assertEqual(
-            ['bug_url', 'displayname', 'name', 'summary'],
+            ['bug_url', 'display_name', 'name', 'summary'],
              view.field_names)
 
     def test_register_project_create_upstream_bugtask_with_packaging(self):
@@ -144,7 +144,7 @@
         form = {
             'field.bug_url': 'http://bugs.foo.org/bugs/show_bug.cgi?id=8',
             'field.name': 'fruit',
-            'field.displayname': 'Fruit',
+            'field.display_name': 'Fruit',
             'field.summary': 'The Fruit summary',
             'field.add_packaging': 'on',
             'field.actions.continue': 'Continue',
@@ -171,7 +171,7 @@
         form = {
             'field.bug_url': 'http://bugs.foo.org/bugs/show_bug.cgi?id=8',
             'field.name': 'fruit',
-            'field.displayname': 'Fruit',
+            'field.display_name': 'Fruit',
             'field.summary': 'The Fruit summary',
             'field.add_packaging': 'on',
             'field.actions.continue': 'Continue',

=== modified file 'lib/lp/bugs/interfaces/bugtask.py'
--- lib/lp/bugs/interfaces/bugtask.py	2015-01-30 18:24:07 +0000
+++ lib/lp/bugs/interfaces/bugtask.py	2015-10-01 17:39:00 +0000
@@ -1060,7 +1060,7 @@
     bug_url = StrippedTextLine(
         title=_('Bug URL'), required=True, constraint=valid_remote_bug_url,
         description=_("The URL of this bug in the remote bug tracker."))
-    displayname = TextLine(title=_('Project name'))
+    display_name = TextLine(title=_('Project name'))
     name = ProductNameField(
         title=_('Project ID'), constraint=name_validator, required=True,
         description=_(

=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
--- lib/lp/bugs/model/tests/test_bugtask.py	2015-10-01 01:42:13 +0000
+++ lib/lp/bugs/model/tests/test_bugtask.py	2015-10-01 17:39:00 +0000
@@ -3135,7 +3135,7 @@
                          u'Mozilla Thunderbird')
 
         thunderbird.name = 'thunderbird-ng'
-        thunderbird.displayname = 'Mozilla Thunderbird NG'
+        thunderbird.display_name = 'Mozilla Thunderbird NG'
 
         # XXX Guilherme Salgado 2005-11-07 bug=3989:
         # This flush_database_updates() shouldn't be needed because we
@@ -3213,7 +3213,7 @@
         # The updating of targetnamecaches is usually done by the cronjob,
         # however it can also be invoked directly.
         thunderbird.name = 'thunderbird'
-        thunderbird.displayname = 'Mozilla Thunderbird'
+        thunderbird.display_name = 'Mozilla Thunderbird'
         transaction.commit()
 
         self.assertEqual(upstream_task.bugtargetdisplayname,

=== modified file 'lib/lp/bugs/templates/bugtask-affects-new-product.pt'
--- lib/lp/bugs/templates/bugtask-affects-new-product.pt	2010-07-24 19:19:16 +0000
+++ lib/lp/bugs/templates/bugtask-affects-new-product.pt	2015-10-01 17:39:00 +0000
@@ -53,7 +53,7 @@
             <metal:block use-macro="context/@@launchpad_form/widget_row" />
           </tal:bug-url>
 
-          <tal:product-name define="widget nocall:widgets/displayname">
+          <tal:product-name define="widget nocall:widgets/display_name">
             <metal:block use-macro="context/@@launchpad_form/widget_row" />
           </tal:product-name>
 

=== modified file 'lib/lp/registry/browser/product.py'
--- lib/lp/registry/browser/product.py	2015-09-30 00:38:30 +0000
+++ lib/lp/registry/browser/product.py	2015-10-01 17:39:00 +0000
@@ -1367,7 +1367,7 @@
     label = "Edit details"
     schema = IProduct
     field_names = [
-        "displayname",
+        "display_name",
         "title",
         "summary",
         "description",
@@ -2151,14 +2151,14 @@
 class ProjectAddStepOne(StepView):
     """product/+new view class for creating a new project."""
 
-    _field_names = ['displayname', 'name', 'summary']
+    _field_names = ['display_name', 'name', 'summary']
     label = "Register a project in Launchpad"
     schema = IProduct
     step_name = 'projectaddstep1'
     template = ViewPageTemplateFile('../templates/product-new.pt')
     page_title = "Register a project in Launchpad"
 
-    custom_widget('displayname', TextWidget, displayWidth=50, label='Name')
+    custom_widget('display_name', TextWidget, displayWidth=50, label='Name')
     custom_widget('name', ProductNameWidget, label='URL')
 
     step_description = 'Project basics'
@@ -2207,7 +2207,7 @@
 class ProjectAddStepTwo(StepView, ProductLicenseMixin, ReturnToReferrerMixin):
     """Step 2 (of 2) in the +new project add wizard."""
 
-    _field_names = ['displayname', 'name', 'summary', 'description',
+    _field_names = ['display_name', 'name', 'summary', 'description',
                     'homepageurl', 'information_type', 'licenses',
                     'license_info', 'driver', 'bug_supervisor', 'owner']
     schema = IProduct
@@ -2217,7 +2217,7 @@
 
     product = None
 
-    custom_widget('displayname', TextWidget, displayWidth=50, label='Name')
+    custom_widget('display_name', TextWidget, displayWidth=50, label='Name')
     custom_widget('name', ProductNameWidget, label='URL')
     custom_widget('homepageurl', TextWidget, displayWidth=30)
     custom_widget('licenses', LicenseWidget)
@@ -2328,7 +2328,7 @@
         # phrasing is different.
         self.widgets['name'].hint = (
             "When published, this will be the project's URL.")
-        self.widgets['displayname'].visible = False
+        self.widgets['display_name'].visible = False
         self.widgets['source_package_name'].visible = False
         self.widgets['distroseries'].visible = False
 
@@ -2364,7 +2364,7 @@
     def _search_string(self):
         """Return the ORed terms to match."""
         search_text = SPACE.join((self.request.form['field.name'],
-                                  self.request.form['field.displayname'],
+                                  self.request.form['field.display_name'],
                                   self.request.form['field.summary']))
         # OR all the terms together.
         return OR.join(search_text.split())
@@ -2413,7 +2413,7 @@
     def label(self):
         """See `LaunchpadFormView`."""
         return 'Register %s (%s) in Launchpad' % (
-                self.request.form['field.displayname'],
+                self.request.form['field.display_name'],
                 self.request.form['field.name'])
 
     def create_product(self, data):
@@ -2433,8 +2433,8 @@
             driver=data.get('driver', None),
             owner=owner,
             name=data['name'],
-            displayname=data['displayname'],
-            title=data['displayname'],
+            display_name=data['display_name'],
+            title=data['display_name'],
             summary=data['summary'],
             description=description,
             homepageurl=data.get('homepageurl'),

=== modified file 'lib/lp/registry/browser/project.py'
--- lib/lp/registry/browser/project.py	2015-07-08 16:05:11 +0000
+++ lib/lp/registry/browser/project.py	2015-10-01 17:39:00 +0000
@@ -386,7 +386,7 @@
     page_title = label
     schema = IProjectGroup
     field_names = [
-        'displayname', 'summary', 'description',
+        'display_name', 'summary', 'description',
         'bug_reporting_guidelines', 'bug_reported_acknowledgement',
         'homepageurl', 'bugtracker', 'sourceforgeproject',
         'wikiurl']
@@ -492,9 +492,9 @@
         return getUtility(IProductSet).createProduct(
             owner=self.user,
             name=data['name'],
-            title=data['displayname'],
+            title=data['display_name'],
             summary=data['summary'],
-            displayname=data['displayname'],
+            display_name=data['display_name'],
             licenses=data['licenses'],
             license_info=data['license_info'],
             information_type=data.get('information_type'),
@@ -505,7 +505,7 @@
     def label(self):
         """See `LaunchpadFormView`."""
         return 'Register %s (%s) in Launchpad as a part of %s' % (
-            self.request.form['displayname'], self.request.form['name'],
+            self.request.form['display_name'], self.request.form['name'],
             self.context.displayname)
 
 
@@ -579,7 +579,7 @@
     schema = IProjectGroup
     field_names = [
         'name',
-        'displayname',
+        'display_name',
         'summary',
         'description',
         'owner',
@@ -595,8 +595,8 @@
         """Create the new Project from the form details."""
         self.projectgroup = getUtility(IProjectGroupSet).new(
             name=data['name'].lower().strip(),
-            displayname=data['displayname'],
-            title=data['displayname'],
+            display_name=data['display_name'],
+            title=data['display_name'],
             homepageurl=data['homepageurl'],
             summary=data['summary'],
             description=data['description'],

=== modified file 'lib/lp/registry/browser/sourcepackage.py'
--- lib/lp/registry/browser/sourcepackage.py	2015-07-29 16:55:28 +0000
+++ lib/lp/registry/browser/sourcepackage.py	2015-10-01 17:39:00 +0000
@@ -96,7 +96,7 @@
 
 
 def get_register_upstream_url(source_package):
-    displayname = string.capwords(source_package.name.replace('-', ' '))
+    display_name = string.capwords(source_package.name.replace('-', ' '))
     distroseries_string = "%s/%s" % (
         source_package.distroseries.distribution.name,
         source_package.distroseries.name)
@@ -110,8 +110,8 @@
         'field.source_package_name': source_package.sourcepackagename.name,
         'field.distroseries': distroseries_string,
         'field.name': source_package.name,
-        'field.displayname': displayname,
-        'field.title': displayname,
+        'field.display_name': display_name,
+        'field.title': display_name,
         'field.homepageurl': homepage,
         'field.__visited_steps__': ProjectAddStepOne.step_name,
         'field.actions.continue': 'Continue',

=== modified file 'lib/lp/registry/browser/tests/project-add-views.txt'
--- lib/lp/registry/browser/tests/project-add-views.txt	2013-04-11 01:33:23 +0000
+++ lib/lp/registry/browser/tests/project-add-views.txt	2015-10-01 17:39:00 +0000
@@ -11,7 +11,7 @@
     >>> view.first_step
     <class 'lp.registry.browser.product.ProjectAddStepOne'>
 
-The first step requires all of name, summary, displayname to be given.  These
+The first step requires all of name, summary, display_name to be given.  These
 are forwarded in the form data to the second step.  The title is also
 forwarded, but is only required by the Zope machinery, not the view.
 
@@ -19,7 +19,7 @@
     >>> form = {
     ...     'field.actions.continue': 'Continue',
     ...     'field.__visited_steps__': ProjectAddStepOne.step_name,
-    ...     'field.displayname': '',
+    ...     'field.display_name': '',
     ...     'field.name': '',
     ...     'field.summary': '',
     ... }
@@ -27,11 +27,11 @@
     >>> view = create_initialized_view(product_set, name='+new', form=form)
     >>> for error in view.view.errors:
     ...     print error
-    ('displayname', 'Name', RequiredMissing('displayname'))
+    ('display_name', 'Name', RequiredMissing('display_name'))
     ('name', 'URL', RequiredMissing('name'))
     ('summary', u'Summary', RequiredMissing('summary'))
 
-    >>> form['field.displayname'] = 'Snowdog'
+    >>> form['field.display_name'] = 'Snowdog'
     >>> form['field.name'] = 'snowdog'
     >>> form['field.summary'] = 'By-tor and the Snowdog'
     >>> view = create_initialized_view(product_set, name='+new', form=form)
@@ -63,7 +63,7 @@
     >>> form = {
     ...     'field.actions.continue': 'Continue',
     ...     'field.__visited_steps__': ProjectAddStepTwo.step_name,
-    ...     'field.displayname': 'Snowdog',
+    ...     'field.display_name': 'Snowdog',
     ...     'field.name': 'snowdog',
     ...     'field.title': 'The Snowdog',
     ...     'field.summary': 'By-tor and the Snowdog',
@@ -86,7 +86,7 @@
     >>> list(view.search_results)
     []
 
-The prospective project's name, displayname and summary are used to search
+The prospective project's name, display_name and summary are used to search
 existing projects for possible matches.  By tweaking the project summary, we
 can see that there are search results available.
 
@@ -138,7 +138,7 @@
     # be processed.
     >>> registrant = factory.makePerson()
     >>> form = {
-    ...     'field.displayname': 'Snowdog',
+    ...     'field.display_name': 'Snowdog',
     ...     'field.name': 'snowdog',
     ...     'field.title': 'The Snowdog',
     ...     'field.summary': 'By-tor and the Snowdog',
@@ -157,7 +157,7 @@
     >>> view.errors
     []
 
-    >>> print product_set.getByName('snowdog').displayname
+    >>> print product_set.getByName('snowdog').display_name
     Snowdog
 
 
@@ -168,7 +168,7 @@
 that's checked for duplicates is the 'name' field.
 
     >>> form = {
-    ...     'field.displayname': 'Cougar',
+    ...     'field.display_name': 'Cougar',
     ...     'field.name': 'snowdog',
     ...     'field.title': 'The Cougar',
     ...     'field.summary': "There's the Cougar!",

=== modified file 'lib/lp/registry/browser/tests/test_product.py'
--- lib/lp/registry/browser/tests/test_product.py	2015-07-15 03:58:56 +0000
+++ lib/lp/registry/browser/tests/test_product.py	2015-10-01 17:39:00 +0000
@@ -127,7 +127,7 @@
         return {
             'field.actions.continue': 'Continue',
             'field.__visited_steps__': ProjectAddStepOne.step_name,
-            'field.displayname': 'Fnord',
+            'field.display_name': 'Fnord',
             'field.name': 'fnord',
             'field.summary': 'fnord summary',
             }
@@ -136,7 +136,7 @@
             'field.actions.continue': 'Continue',
             'field.__visited_steps__': '%s|%s' % (
                 ProjectAddStepOne.step_name, ProjectAddStepTwo.step_name),
-            'field.displayname': 'Fnord',
+            'field.display_name': 'Fnord',
             'field.name': 'fnord',
             'field.summary': 'fnord summary',
             'field.disclaim_maintainer': 'off',
@@ -204,13 +204,13 @@
         disclaim_widget = view.view.widgets['disclaim_maintainer']
         self.assertEqual('subordinate', disclaim_widget.cssClass)
         self.assertEqual(
-            ['displayname', 'name', 'summary', 'description',
+            ['display_name', 'name', 'summary', 'description',
              'homepageurl', 'information_type', 'licenses', 'license_info',
              'driver', 'bug_supervisor', 'owner',
              '__visited_steps__'],
             view.view.field_names)
         self.assertEqual(
-            ['displayname', 'name', 'summary', 'description',
+            ['display_name', 'name', 'summary', 'description',
              'homepageurl', 'information_type', 'licenses', 'driver',
              'bug_supervisor', 'owner', 'disclaim_maintainer',
              'source_package_name', 'distroseries', '__visited_steps__',
@@ -565,7 +565,7 @@
         return {
             'field.actions.change': 'Change',
             'field.name': product.name,
-            'field.displayname': product.displayname,
+            'field.display_name': product.display_name,
             'field.title': product.title,
             'field.summary': product.summary,
             'field.information_type': information_type,

=== modified file 'lib/lp/registry/browser/tests/test_sourcepackage_views.py'
--- lib/lp/registry/browser/tests/test_sourcepackage_views.py	2015-07-08 16:05:11 +0000
+++ lib/lp/registry/browser/tests/test_sourcepackage_views.py	2015-10-01 17:39:00 +0000
@@ -82,7 +82,7 @@
              '+source/python-super-package'),
             ('field.__visited_steps__', 'projectaddstep1'),
             ('field.actions.continue', 'Continue'),
-            ('field.displayname', 'Python Super Package'),
+            ('field.display_name', 'Python Super Package'),
             ('field.distroseries', 'zoobuntu/walrus'),
             ('field.name', 'python-super-package'),
             ('field.source_package_name', 'python-super-package'),
@@ -90,7 +90,7 @@
             ]
         self.assertEqual(expected_params, params)
 
-    def test_get_register_upstream_url_displayname(self):
+    def test_get_register_upstream_url_display_name(self):
         # The sourcepackagename 'python-super-package' is split on
         # the hyphens, and each word is capitalized.
         distroseries = self.factory.makeDistroSeries(
@@ -101,7 +101,7 @@
             sourcepackagename='python-super-package')
         url = get_register_upstream_url(source_package)
         self.assertInQueryString(
-            url, 'field.displayname', 'Python Super Package')
+            url, 'field.display_name', 'Python Super Package')
 
     def test_get_register_upstream_url_summary(self):
         source_package = self._makePublishedSourcePackage()

=== modified file 'lib/lp/registry/configure.zcml'
--- lib/lp/registry/configure.zcml	2015-10-01 10:25:19 +0000
+++ lib/lp/registry/configure.zcml	2015-10-01 17:39:00 +0000
@@ -1340,7 +1340,7 @@
                 commercial_subscription
                 description
                 development_focus
-                displayname
+                display_name
                 downloadurl
                 driver
                 freshmeatproject

=== modified file 'lib/lp/registry/doc/product.txt'
--- lib/lp/registry/doc/product.txt	2015-06-26 12:57:00 +0000
+++ lib/lp/registry/doc/product.txt	2015-10-01 17:39:00 +0000
@@ -305,7 +305,7 @@
     >>> product = productset.createProduct(
     ...     owner=owner,
     ...     name='test-product',
-    ...     displayname='Test Product',
+    ...     display_name='Test Product',
     ...     title='Test Product',
     ...     summary='A test product',
     ...     description='A description of the test product',

=== modified file 'lib/lp/registry/interfaces/product.py'
--- lib/lp/registry/interfaces/product.py	2015-09-17 11:12:42 +0000
+++ lib/lp/registry/interfaces/product.py	2015-10-01 17:39:00 +0000
@@ -409,13 +409,15 @@
     on bugs, branches or specifications for the product.
     """
 
-    displayname = exported(
+    display_name = exported(
         TextLine(
             title=_('Display Name'),
             description=_("""The name of the project as it would appear in a
                 paragraph.""")),
         exported_as='display_name')
 
+    displayname = Attribute('Display name (deprecated)')
+
     icon = exported(
         IconImageUpload(
             title=_("Icon"), required=False,
@@ -986,21 +988,21 @@
 
     @call_with(owner=REQUEST_USER)
     @rename_parameters_as(
-        displayname='display_name', projectgroup='project_group',
+        projectgroup='project_group',
         homepageurl='home_page_url', screenshotsurl='screenshots_url',
         freshmeatproject='freshmeat_project', wikiurl='wiki_url',
         downloadurl='download_url',
         sourceforgeproject='sourceforge_project',
         programminglang='programming_lang')
     @export_factory_operation(
-        IProduct, ['name', 'displayname', 'title', 'summary', 'description',
+        IProduct, ['name', 'display_name', 'title', 'summary', 'description',
                    'projectgroup', 'homepageurl', 'screenshotsurl',
                    'downloadurl', 'freshmeatproject', 'wikiurl',
                    'sourceforgeproject', 'programminglang',
                    'project_reviewed', 'licenses', 'license_info',
                    'registrant', 'bug_supervisor', 'driver'])
     @export_operation_as('new_project')
-    def createProduct(owner, name, displayname, title, summary,
+    def createProduct(owner, name, display_name, title, summary,
                       description=None, projectgroup=None, homepageurl=None,
                       screenshotsurl=None, wikiurl=None,
                       downloadurl=None, freshmeatproject=None,

=== modified file 'lib/lp/registry/interfaces/projectgroup.py'
--- lib/lp/registry/interfaces/projectgroup.py	2015-01-29 13:09:37 +0000
+++ lib/lp/registry/interfaces/projectgroup.py	2015-10-01 17:39:00 +0000
@@ -151,15 +151,16 @@
             description=_("Project group registrant. Must be a valid "
                           "Launchpad Person.")))
 
-    displayname = exported(
+    display_name = exported(
         TextLine(
             title=_('Display Name'),
             description=_(
                 "Appropriately capitalised, "
                 'and typically ending in "Project". '
                 "Examples: the Apache Project, the Mozilla Project, "
-                "the Gimp Project.")),
-        exported_as="display_name")
+                "the Gimp Project.")))
+
+    displayname = Attribute('Display name (deprecated)')
 
     title = exported(
         Title(

=== modified file 'lib/lp/registry/javascript/product_views.js'
--- lib/lp/registry/javascript/product_views.js	2014-01-30 15:04:06 +0000
+++ lib/lp/registry/javascript/product_views.js	2015-10-01 17:39:00 +0000
@@ -146,7 +146,7 @@
          */
         _bind_name_field: function () {
             var url_field = Y.one('input[id="field.name"]');
-            var name_field = Y.one('input[id="field.displayname"]');
+            var name_field = Y.one('input[id="field.display_name"]');
             name_field.on('keyup', this._url_autofill, this);
 
             // Explicitly typing into the URL field disables autofilling.

=== modified file 'lib/lp/registry/javascript/tests/test_product_views.html'
--- lib/lp/registry/javascript/tests/test_product_views.html	2014-04-03 13:11:12 +0000
+++ lib/lp/registry/javascript/tests/test_product_views.html	2015-10-01 17:39:00 +0000
@@ -82,7 +82,7 @@
         </tr>
         <tr>
             <td>
-                <input type="text" id="field.displayname" name="field.displayname" />
+                <input type="text" id="field.display_name" name="field.display_name" />
             </td>
         </tr>
         <tr>

=== modified file 'lib/lp/registry/javascript/tests/test_product_views.js'
--- lib/lp/registry/javascript/tests/test_product_views.js	2015-06-26 10:58:04 +0000
+++ lib/lp/registry/javascript/tests/test_product_views.js	2015-10-01 17:39:00 +0000
@@ -75,7 +75,7 @@
             var view = new ns.NewProduct();
             view.render();
 
-            var name_field = Y.one('input[id="field.displayname"]');
+            var name_field = Y.one('input[id="field.display_name"]');
             name_field.set('value', 'test');
             name_field.simulate('keyup');
 
@@ -89,7 +89,7 @@
             var view = new ns.NewProduct();
             view.render();
 
-            var name_field = Y.one('input[id="field.displayname"]');
+            var name_field = Y.one('input[id="field.display_name"]');
             var url_field = Y.one('input[id="field.name"]');
             name_field.set('value', 'test');
             name_field.simulate('keyup');

=== modified file 'lib/lp/registry/model/person.py'
--- lib/lp/registry/model/person.py	2015-10-01 10:25:19 +0000
+++ lib/lp/registry/model/person.py	2015-10-01 17:39:00 +0000
@@ -1095,7 +1095,7 @@
             clauses.append(
                 Or(
                     Product.name.contains_string(match_name),
-                    Product.displayname.contains_string(match_name),
+                    Product.display_name.contains_string(match_name),
                     fti_search(Product, match_name)))
 
         if user is not None:
@@ -1103,7 +1103,7 @@
 
         return IStore(Product).find(
             Product, *clauses
-            ).config(distinct=True).order_by(Product.displayname)
+            ).config(distinct=True).order_by(Product.display_name)
 
     def isAnyPillarOwner(self):
         """See IPerson."""

=== modified file 'lib/lp/registry/model/product.py'
--- lib/lp/registry/model/product.py	2015-09-28 17:38:45 +0000
+++ lib/lp/registry/model/product.py	2015-10-01 17:39:00 +0000
@@ -392,7 +392,7 @@
         notNull=False, default=None)
     name = StringCol(
         dbName='name', notNull=True, alternateID=True, unique=True)
-    displayname = StringCol(dbName='displayname', notNull=True)
+    display_name = StringCol(dbName='displayname', notNull=True)
     _title = StringCol(dbName='title', notNull=True)
     summary = StringCol(dbName='summary', notNull=True)
     description = StringCol(notNull=False, default=None)
@@ -436,8 +436,12 @@
     vcs = EnumCol(enum=VCSType, notNull=False)
 
     @property
+    def displayname(self):
+        return self.display_name
+
+    @property
     def title(self):
-        return self.displayname
+        return self.display_name
 
     @property
     def date_next_suggest_packaging(self):
@@ -1276,7 +1280,7 @@
     @property
     def bugtargetdisplayname(self):
         """See IBugTarget."""
-        return self.displayname
+        return self.display_name
 
     @property
     def bugtargetname(self):
@@ -1909,7 +1913,7 @@
             results = results.limit(num_products)
         return results
 
-    def createProduct(self, owner, name, displayname, title, summary,
+    def createProduct(self, owner, name, display_name, title, summary,
                       description=None, projectgroup=None, homepageurl=None,
                       screenshotsurl=None, wikiurl=None,
                       downloadurl=None, freshmeatproject=None,
@@ -1937,7 +1941,7 @@
                     ' Projects.')
         product = Product(
             owner=owner, registrant=registrant, name=name,
-            displayname=displayname, _title=title, projectgroup=projectgroup,
+            display_name=display_name, _title=title, projectgroup=projectgroup,
             summary=summary, description=description, homepageurl=homepageurl,
             screenshotsurl=screenshotsurl, wikiurl=wikiurl,
             downloadurl=downloadurl, freshmeatproject=None,
@@ -2081,7 +2085,7 @@
         result = IStore(Product).find(
             Product, *conditions).config(
                 distinct=True).order_by(
-                    Product.datecreated, Product.displayname)
+                    Product.datecreated, Product.display_name)
 
         def eager_load(products):
             return get_precached_products(
@@ -2121,7 +2125,7 @@
             POTemplate.productseriesID == ProductSeries.id,
             Product.translations_usage == ServiceUsage.LAUNCHPAD,
             Person.id == Product._ownerID).config(
-                distinct=True).order_by(Product.displayname)
+                distinct=True).order_by(Product.display_name)
 
         # We only want Product - the other tables are just to populate
         # the cache.

=== modified file 'lib/lp/registry/model/projectgroup.py'
--- lib/lp/registry/model/projectgroup.py	2015-07-08 16:05:11 +0000
+++ lib/lp/registry/model/projectgroup.py	2015-10-01 17:39:00 +0000
@@ -126,7 +126,7 @@
         dbName='registrant', foreignKey='Person',
         storm_validator=validate_public_person, notNull=True)
     name = StringCol(dbName='name', notNull=True)
-    displayname = StringCol(dbName='displayname', notNull=True)
+    display_name = StringCol(dbName='displayname', notNull=True)
     _title = StringCol(dbName='title', notNull=True)
     summary = StringCol(dbName='summary', notNull=True)
     description = StringCol(dbName='description', notNull=True)
@@ -162,8 +162,12 @@
     bug_reported_acknowledgement = StringCol(default=None)
 
     @property
+    def displayname(self):
+        return self.display_name
+
+    @property
     def title(self):
-        return self.displayname
+        return self.display_name
 
     @property
     def pillar_category(self):
@@ -174,7 +178,7 @@
         results = Store.of(self).find(
             Product, Product.projectgroup == self, Product.active == True,
             ProductSet.getProductPrivacyFilter(user))
-        return results.order_by(Product.displayname)
+        return results.order_by(Product.display_name)
 
     @cachedproperty
     def products(self):
@@ -549,7 +553,7 @@
             return None
         return pillar
 
-    def new(self, name, displayname, title, homepageurl, summary,
+    def new(self, name, display_name, title, homepageurl, summary,
             description, owner, mugshot=None, logo=None, icon=None,
             registrant=None, bug_supervisor=None, driver=None):
         """See `lp.registry.interfaces.projectgroup.IProjectGroupSet`."""
@@ -557,7 +561,7 @@
             registrant = owner
         return ProjectGroup(
             name=name,
-            displayname=displayname,
+            display_name=display_name,
             _title=title,
             summary=summary,
             description=description,

=== modified file 'lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt'
--- lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt	2015-06-27 04:10:49 +0000
+++ lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt	2015-10-01 17:39:00 +0000
@@ -82,7 +82,7 @@
     >>> user_browser.getControl("Link to Upstream Project").click()
     >>> print user_browser.getControl(name='field.name').value
     bonkers
-    >>> print user_browser.getControl(name='field.displayname').value
+    >>> print user_browser.getControl(name='field.display_name').value
     Bonkers
     >>> print user_browser.getControl(name='field.summary').value
     summary for flubber-bin
@@ -106,7 +106,7 @@
     >>> user_browser.getLink("Register the upstream project").click()
     >>> print user_browser.getControl(name='field.name').value
     bonkers
-    >>> print user_browser.getControl(name='field.displayname').value
+    >>> print user_browser.getControl(name='field.display_name').value
     Bonkers
     >>> print user_browser.getControl(name='field.summary').value
     summary for flubber-bin

=== modified file 'lib/lp/registry/stories/project/xx-project-add-product.txt'
--- lib/lp/registry/stories/project/xx-project-add-product.txt	2015-06-26 12:57:00 +0000
+++ lib/lp/registry/stories/project/xx-project-add-product.txt	2015-10-01 17:39:00 +0000
@@ -15,7 +15,7 @@
 process.  Fill in the first page and then 'Continue' which will keep
 us on the same page.
 
-    >>> browser.getControl(name='field.displayname').value = 'Eye of GNOME'
+    >>> browser.getControl(name='field.display_name').value = 'Eye of GNOME'
     >>> browser.getControl(name='field.name', index=0).value = 'eog'
     >>> browser.getControl(name='field.summary').value = 'An image viewer for GNOME'
     >>> browser.getControl('Continue').click()

=== modified file 'lib/lp/registry/templates/product-new.pt'
--- lib/lp/registry/templates/product-new.pt	2012-09-19 10:38:17 +0000
+++ lib/lp/registry/templates/product-new.pt	2015-10-01 17:39:00 +0000
@@ -81,7 +81,7 @@
           <img src="/@@/info" />
           There are similar projects already registered in Launchpad.
           Is project
-          <strong><tal:displayname tal:replace="view/request/field.displayname" />
+          <strong><tal:display_name tal:replace="view/request/field.display_name" />
           (<tal:name  tal:replace="view/request/field.name" />)</strong>
           one of these?
           </div>
@@ -108,7 +108,7 @@
               tal:condition="view/search_results_count"
               >Registration details</h3>
           Select the licences for project
-          <strong><tal:displayname tal:replace="view/request/field.displayname" />
+          <strong><tal:display_name tal:replace="view/request/field.display_name" />
           (<tal:name  tal:replace="view/request/field.name" />)</strong>
           and complete the registration.  You may also update the project's
           title and summary.

=== modified file 'lib/lp/registry/tests/test_person.py'
--- lib/lp/registry/tests/test_person.py	2015-09-29 01:38:34 +0000
+++ lib/lp/registry/tests/test_person.py	2015-10-01 17:39:00 +0000
@@ -553,9 +553,9 @@
         person = self.factory.makePerson()
         product = self.factory.makeProduct()
         with person_logged_in(person):
-            self.assertFalse(person.canWrite(product, 'displayname'))
+            self.assertFalse(person.canWrite(product, 'display_name'))
         with person_logged_in(product.owner):
-            self.assertTrue(product.owner.canWrite(product, 'displayname'))
+            self.assertTrue(product.owner.canWrite(product, 'display_name'))
 
     def test_canWrite__checking_permissions_of_others(self):
         # Logged in users cannot call Person.canWrite() on Person

=== modified file 'lib/lp/registry/tests/test_product.py'
--- lib/lp/registry/tests/test_product.py	2015-07-07 22:33:29 +0000
+++ lib/lp/registry/tests/test_product.py	2015-10-01 17:39:00 +0000
@@ -832,7 +832,7 @@
             'active', 'id', 'information_type', 'pillar_category', 'private',
             'userCanLimitedView', 'userCanView',)),
         'launchpad.LimitedView': set((
-            'bugtargetdisplayname', 'displayname', 'drivers',
+            'bugtargetdisplayname', 'display_name', 'displayname', 'drivers',
             'enable_bug_expiration', 'getBugTaskWeightFunction',
             'getSpecification',
             'icon', 'logo', 'name', 'official_answers', 'official_anything',
@@ -934,7 +934,7 @@
                 'answers_usage', 'blueprints_usage', 'bug_supervisor',
                 'bug_tracking_usage', 'codehosting_usage',
                 'commercial_subscription', 'description', 'development_focus',
-                'displayname', 'downloadurl', 'driver', 'freshmeatproject',
+                'display_name', 'downloadurl', 'driver', 'freshmeatproject',
                 'homepage_content', 'homepageurl', 'icon', 'information_type',
                 'license_info', 'licenses', 'logo', 'mugshot',
                 'official_answers', 'official_blueprints',

=== modified file 'lib/lp/registry/tests/test_subscribers.py'
--- lib/lp/registry/tests/test_subscribers.py	2013-02-06 04:22:43 +0000
+++ lib/lp/registry/tests/test_subscribers.py	2015-10-01 17:39:00 +0000
@@ -230,7 +230,7 @@
     def test_display_escapee_user_data(self):
         # A notification is added if there is a message to show.
         product, user = self.make_product_user([License.OTHER_PROPRIETARY])
-        product.displayname = '<b>Look</b>'
+        product.display_name = '<b>Look</b>'
         notification = LicenseNotification(product)
         result = notification.display()
         self.assertIs(True, result)

=== modified file 'lib/lp/services/salesforce/doc/voucher.txt'
--- lib/lp/services/salesforce/doc/voucher.txt	2012-12-26 01:32:19 +0000
+++ lib/lp/services/salesforce/doc/voucher.txt	2015-10-01 17:39:00 +0000
@@ -84,7 +84,7 @@
     >>> voucher = vouchers[0]['voucher_id']
     >>> result = server.redeemVoucher(
     ...     voucher, mark_identifier,
-    ...     firefox.id, firefox.displayname)
+    ...     firefox.id, firefox.display_name)
     >>> print result
     True
     >>> vouchers = server.getUnredeemedVouchers(mark_identifier)
@@ -112,7 +112,7 @@
     >>> voucher = vouchers[0]['voucher_id']
     >>> result = server.redeemVoucher(
     ...     voucher, mark_identifier,
-    ...     firefox.id, firefox.displayname)
+    ...     firefox.id, firefox.display_name)
     Traceback (most recent call last):
       ...
     Fault: <Fault NotFound: 'Something was not found.'>
@@ -251,10 +251,10 @@
 
     >>> from zope.security.proxy import removeSecurityProxy
     >>> naked_firefox = removeSecurityProxy(firefox)
-    >>> print naked_firefox.displayname
+    >>> print naked_firefox.display_name
     Mozilla Firefox
-    >>> naked_firefox.displayname = 'Super Mozilla Firefox'
-    >>> print naked_firefox.displayname
+    >>> naked_firefox.display_name = 'Super Mozilla Firefox'
+    >>> print naked_firefox.display_name
     Super Mozilla Firefox
     >>> result = voucher_proxy.updateProjectName(naked_firefox)
     >>> print result

=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py	2015-09-15 20:16:47 +0000
+++ lib/lp/testing/factory.py	2015-10-01 17:39:00 +0000
@@ -1049,7 +1049,7 @@
             title = self.getUniqueString('title')
         project = getUtility(IProjectGroupSet).new(
             name=name,
-            displayname=displayname,
+            display_name=displayname,
             title=title,
             homepageurl=homepageurl,
             summary=summary,

=== modified file 'lib/lp/translations/model/translationgroup.py'
--- lib/lp/translations/model/translationgroup.py	2015-07-08 16:05:11 +0000
+++ lib/lp/translations/model/translationgroup.py	2015-10-01 17:39:00 +0000
@@ -203,7 +203,7 @@
         product_data = ISlaveStore(Product).using(*using).find(
             columns,
             Product.translationgroupID == self.id, Product.active == True)
-        product_data = product_data.order_by(Product.displayname)
+        product_data = product_data.order_by(Product.display_name)
 
         return [
             ProductWithLicenses(product, tuple(licenses))
@@ -230,7 +230,7 @@
         project_data = ISlaveStore(ProjectGroup).using(*using).find(
             tables,
             ProjectGroup.translationgroupID == self.id,
-            ProjectGroup.active == True).order_by(ProjectGroup.displayname)
+            ProjectGroup.active == True).order_by(ProjectGroup.display_name)
 
         return DecoratedResultSet(project_data, operator.itemgetter(0))
 


Follow ups