Hello community,

here is the log from the commit of package python-oslo.versionedobjects for 
openSUSE:Factory checked in at 2017-02-21 13:42:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-oslo.versionedobjects (Old)
 and      /work/SRC/openSUSE:Factory/.python-oslo.versionedobjects.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-oslo.versionedobjects"

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-oslo.versionedobjects/python-oslo.versionedobjects.changes
        2016-10-13 11:29:00.000000000 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-oslo.versionedobjects.new/python-oslo.versionedobjects.changes
   2017-02-21 13:42:35.509953150 +0100
@@ -1,0 +2,24 @@
+Mon Feb 13 09:51:44 UTC 2017 - [email protected]
+
+- update to version 1.21.0:
+  - Fix documentation typo
+  - Fix a typo
+  - Add Constraints support
+  - Fix incorrect timestamp comment
+  - Add reno for release notes management
+  - Show team and repo badges on README
+  - Changed the home-page link
+  - Fix recursive deepcopy
+  - Replace six.iteritems() with .items()
+  - Add ObjectListBase concat methods
+  - Fix get_schema() for Enum
+  - JSON Schema get_schema implementation for last few fields
+  - Refactor get_schema for patterned FieldTypes
+  - Updated from global requirements
+
+-------------------------------------------------------------------
+Fri Oct 14 14:09:00 UTC 2016 - [email protected]
+
+- Fix Url
+
+-------------------------------------------------------------------

Old:
----
  oslo.versionedobjects-1.17.0.tar.gz

New:
----
  oslo.versionedobjects-1.21.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-oslo.versionedobjects.spec ++++++
--- /var/tmp/diff_new_pack.lDJDXg/_old  2017-02-21 13:42:35.929893908 +0100
+++ /var/tmp/diff_new_pack.lDJDXg/_new  2017-02-21 13:42:35.933893343 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-oslo.versionedobjects
 #
-# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,38 +17,40 @@
 
 
 Name:           python-oslo.versionedobjects
-Version:        1.17.0
+Version:        1.21.0
 Release:        0
 Summary:        Oslo Versioned Objects library
 License:        Apache-2.0
 Group:          Development/Languages/Python
-Url:            http://launchpad.net/oslo
+Url:            http://launchpad.net/%{sname}
 Source0:        
https://pypi.io/packages/source/o/oslo.versionedobjects/oslo.versionedobjects-%{version}.tar.gz
 BuildRequires:  openstack-macros
 BuildRequires:  python-devel
 BuildRequires:  python-iso8601 >= 0.1.11
+BuildRequires:  python-jsonschema >= 2.0.0
 BuildRequires:  python-oslo.concurrency >= 3.8.0
 BuildRequires:  python-oslo.config >= 3.14.0
 BuildRequires:  python-oslo.context >= 2.9.0
 BuildRequires:  python-oslo.i18n >= 2.1.0
-BuildRequires:  python-oslo.log >= 1.14.0
-BuildRequires:  python-oslo.messaging >= 5.2.0
+BuildRequires:  python-oslo.log >= 3.11.0
+BuildRequires:  python-oslo.messaging >= 5.14.0
 BuildRequires:  python-oslo.serialization >= 1.10.0
-BuildRequires:  python-oslo.utils >= 3.16.0
+BuildRequires:  python-oslo.utils >= 3.18.0
 BuildRequires:  python-oslotest >= 1.10.0
-BuildRequires:  python-pbr >= 1.6
+BuildRequires:  python-pbr >= 1.8
 BuildRequires:  python-testtools >= 1.4.0
-Requires:       python-WebOb >= 1.2.3
+Requires:       python-WebOb >= 1.6.0
 Requires:       python-iso8601 >= 0.1.11
+Requires:       python-jsonschema >= 2.0.0
 Requires:       python-netaddr >= 0.7.13
 Requires:       python-oslo.concurrency >= 3.8.0
 Requires:       python-oslo.config >= 3.14.0
 Requires:       python-oslo.context >= 2.9.0
 Requires:       python-oslo.i18n >= 2.1.0
-Requires:       python-oslo.log >= 1.14.0
-Requires:       python-oslo.messaging >= 5.2.0
+Requires:       python-oslo.log >= 3.11.0
+Requires:       python-oslo.messaging >= 5.14.0
 Requires:       python-oslo.serialization >= 1.10.0
-Requires:       python-oslo.utils >= 3.16.0
+Requires:       python-oslo.utils >= 3.18.0
 Requires:       python-six >= 1.9.0
 BuildArch:      noarch
 
@@ -64,14 +66,15 @@
 Summary:        osloversionedobjects library - Documentation
 Group:          Documentation/HTML
 BuildRequires:  python-Sphinx
-BuildRequires:  python-oslosphinx >= 2.5.0
+BuildRequires:  python-oslosphinx >= 4.7.0
 Requires:       %{name} = %{version}
 
 %description doc
 This package contains documentation files for %{name}.
 
 %prep
-%setup -q -n oslo.versionedobjects-%{version}
+%autosetup -n oslo.versionedobjects-%{version}
+%py_req_cleanup
 
 %build
 %{py2_build}
@@ -85,7 +88,7 @@
 
 %files
 %license LICENSE
-%doc README.rst ChangeLog AUTHORS
+%doc README.rst ChangeLog
 %{python2_sitelib}/*
 
 %files doc

++++++ _service ++++++
--- /var/tmp/diff_new_pack.lDJDXg/_old  2017-02-21 13:42:35.969888265 +0100
+++ /var/tmp/diff_new_pack.lDJDXg/_new  2017-02-21 13:42:35.969888265 +0100
@@ -1,11 +1,12 @@
 <services>
   <service mode="disabled" name="renderspec">
-    <param 
name="input-template">https://raw.githubusercontent.com/openstack/rpm-packaging/stable/newton/openstack/oslo.versionedobjects/oslo.versionedobjects.spec.j2</param>
+    <param 
name="input-template">https://raw.githubusercontent.com/openstack/rpm-packaging/stable/ocata/openstack/oslo.versionedobjects/oslo.versionedobjects.spec.j2</param>
     <param name="output-name">python-oslo.versionedobjects.spec</param>
-    <param 
name="requirements">https://raw.githubusercontent.com/openstack/rpm-packaging/stable/newton/global-requirements.txt</param>
+    <param 
name="requirements">https://raw.githubusercontent.com/openstack/rpm-packaging/stable/ocata/global-requirements.txt</param>
+    <param name="changelog-email">[email protected]</param>
+    <param name="changelog-provider">gh,openstack,oslo.versionedobjects</param>
   </service>
   <service mode="disabled" name="download_files">
-    <param name="changesgenerate">enable</param>
   </service>
   <service name="format_spec_file" mode="disabled"/>
 </services>

++++++ oslo.versionedobjects-1.17.0.tar.gz -> 
oslo.versionedobjects-1.21.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.versionedobjects-1.17.0/AUTHORS 
new/oslo.versionedobjects-1.21.0/AUTHORS
--- old/oslo.versionedobjects-1.17.0/AUTHORS    2016-08-25 14:02:00.000000000 
+0200
+++ new/oslo.versionedobjects-1.21.0/AUTHORS    2017-01-18 15:11:40.000000000 
+0100
@@ -109,9 +109,11 @@
 Eugeniya Kudryashova <[email protected]>
 Ewan Mellor <[email protected]>
 Feodor Tersin <[email protected]>
+Flavio Percoco <[email protected]>
 Gabe Westmaas <[email protected]>
 Gary Kotton <[email protected]>
 Gary Kotton <[email protected]>
+Gevorg Davoian <[email protected]>
 Ghe Rivero <[email protected]>
 Graham Hayes <[email protected]>
 Grant Murphy <[email protected]>
@@ -168,6 +170,7 @@
 Joshua McKenty <[email protected]>
 Joshua McKenty <[email protected]>
 Julian Sy <[email protected]>
+Julian Sy <[email protected]>
 Julien Danjou <[email protected]>
 Julien Danjou <[email protected]>
 Justin SB <[email protected]>
@@ -182,6 +185,7 @@
 Keisuke Tagami <[email protected]>
 Ken Pepple <[email protected]>
 Ken'ichi Ohmichi <[email protected]>
+Kevin Benton <[email protected]>
 Kevin L. Mitchell <[email protected]>
 Koji Iida <[email protected]>
 Krisztian Gacsal <[email protected]>
@@ -193,6 +197,7 @@
 Liang Chen <[email protected]>
 Lianhao Lu <[email protected]>
 Lorin Hochstein <[email protected]>
+Luong Anh Tuan <[email protected]>
 Lvov Maxim <[email protected]>
 MORITA Kazutaka <[email protected]>
 Mark McLoughlin <[email protected]>
@@ -288,6 +293,7 @@
 Sergey Nikitin <[email protected]>
 Sergey Skripnick <[email protected]>
 Sergey Vilgelm <[email protected]>
+Serhii Skrypnik <[email protected]>
 Shane Wang <[email protected]>
 Shlomi Sasson <[email protected]>
 Shuangtai Tian <[email protected]>
@@ -346,6 +352,7 @@
 danwent <danwent@dan-xs3-cs>
 [email protected] <>
 fujioka yuuichi <[email protected]>
+gecong1973 <[email protected]>
 guohliu <[email protected]>
 hartsocks <[email protected]>
 ivan-zhu <[email protected]>
@@ -361,6 +368,7 @@
 [email protected] <>
 mdietz <mdietz@openstack>
 melanie witt <[email protected]>
+melissaml <[email protected]>
 pengyuwei <[email protected]>
 root <root@tonbuntu>
 root <root@ubuntu>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.versionedobjects-1.17.0/ChangeLog 
new/oslo.versionedobjects-1.21.0/ChangeLog
--- old/oslo.versionedobjects-1.17.0/ChangeLog  2016-08-25 14:02:00.000000000 
+0200
+++ new/oslo.versionedobjects-1.21.0/ChangeLog  2017-01-18 15:11:40.000000000 
+0100
@@ -1,6 +1,44 @@
 CHANGES
 =======
 
+1.21.0
+------
+
+* Add Constraints support
+* Replace six.iteritems() with .items()
+* Updated from global requirements
+
+1.20.0
+------
+
+
+1.19.0
+------
+
+* Fix a typo
+* Show team and repo badges on README
+* Updated from global requirements
+* Add reno for release notes management
+* Refactor get_schema for patterned FieldTypes
+* Updated from global requirements
+* Fix recursive deepcopy
+* Updated from global requirements
+* Fix get_schema() for Enum
+
+1.18.0
+------
+
+* Changed the home-page link
+* Updated from global requirements
+* Changed the home-page link
+* Updated from global requirements
+* JSON Schema get_schema implementation for last few fields
+* Updated from global requirements
+* Add ObjectListBase concat methods
+* Fix documentation typo
+* Fix incorrect timestamp comment
+* Updated from global requirements
+
 1.17.0
 ------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.versionedobjects-1.17.0/PKG-INFO 
new/oslo.versionedobjects-1.21.0/PKG-INFO
--- old/oslo.versionedobjects-1.17.0/PKG-INFO   2016-08-25 14:02:00.000000000 
+0200
+++ new/oslo.versionedobjects-1.21.0/PKG-INFO   2017-01-18 15:11:41.000000000 
+0100
@@ -1,12 +1,21 @@
 Metadata-Version: 1.1
 Name: oslo.versionedobjects
-Version: 1.17.0
+Version: 1.21.0
 Summary: Oslo Versioned Objects library
-Home-page: http://launchpad.net/oslo
+Home-page: http://docs.openstack.org/developer/oslo.versionedobjects
 Author: OpenStack
 Author-email: [email protected]
 License: UNKNOWN
-Description: ===================================
+Description: ========================
+        Team and repository tags
+        ========================
+        
+        .. image:: 
http://governance.openstack.org/badges/oslo.versionedobjects.svg
+            :target: http://governance.openstack.org/reference/tags/index.html
+        
+        .. Change things from this point on
+        
+        ===================================
         oslo.versionedobjects
         ===================================
         
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.versionedobjects-1.17.0/README.rst 
new/oslo.versionedobjects-1.21.0/README.rst
--- old/oslo.versionedobjects-1.17.0/README.rst 2016-08-25 14:00:20.000000000 
+0200
+++ new/oslo.versionedobjects-1.21.0/README.rst 2017-01-18 15:09:53.000000000 
+0100
@@ -1,3 +1,12 @@
+========================
+Team and repository tags
+========================
+
+.. image:: http://governance.openstack.org/badges/oslo.versionedobjects.svg
+    :target: http://governance.openstack.org/reference/tags/index.html
+
+.. Change things from this point on
+
 ===================================
 oslo.versionedobjects
 ===================================
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.versionedobjects-1.17.0/doc/source/usage.rst 
new/oslo.versionedobjects-1.21.0/doc/source/usage.rst
--- old/oslo.versionedobjects-1.17.0/doc/source/usage.rst       2016-08-25 
14:00:20.000000000 +0200
+++ new/oslo.versionedobjects-1.21.0/doc/source/usage.rst       2017-01-18 
15:09:53.000000000 +0100
@@ -77,7 +77,7 @@
 :class:`oslo_versionedobjects.field.Field` and overwriting the `from_primitive`
 and `to_primitive` methods.
 
-By subclassing :class:oslo_versionedobjects.fields.AutoTypedField you can
+By subclassing :class:`oslo_versionedobjects.fields.AutoTypedField` you can
 stack multiple fields together, making sure even nested data structures are
 being validated.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.versionedobjects-1.17.0/oslo.versionedobjects.egg-info/PKG-INFO 
new/oslo.versionedobjects-1.21.0/oslo.versionedobjects.egg-info/PKG-INFO
--- old/oslo.versionedobjects-1.17.0/oslo.versionedobjects.egg-info/PKG-INFO    
2016-08-25 14:02:00.000000000 +0200
+++ new/oslo.versionedobjects-1.21.0/oslo.versionedobjects.egg-info/PKG-INFO    
2017-01-18 15:11:40.000000000 +0100
@@ -1,12 +1,21 @@
 Metadata-Version: 1.1
 Name: oslo.versionedobjects
-Version: 1.17.0
+Version: 1.21.0
 Summary: Oslo Versioned Objects library
-Home-page: http://launchpad.net/oslo
+Home-page: http://docs.openstack.org/developer/oslo.versionedobjects
 Author: OpenStack
 Author-email: [email protected]
 License: UNKNOWN
-Description: ===================================
+Description: ========================
+        Team and repository tags
+        ========================
+        
+        .. image:: 
http://governance.openstack.org/badges/oslo.versionedobjects.svg
+            :target: http://governance.openstack.org/reference/tags/index.html
+        
+        .. Change things from this point on
+        
+        ===================================
         oslo.versionedobjects
         ===================================
         
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.versionedobjects-1.17.0/oslo.versionedobjects.egg-info/SOURCES.txt 
new/oslo.versionedobjects-1.21.0/oslo.versionedobjects.egg-info/SOURCES.txt
--- old/oslo.versionedobjects-1.17.0/oslo.versionedobjects.egg-info/SOURCES.txt 
2016-08-25 14:02:00.000000000 +0200
+++ new/oslo.versionedobjects-1.21.0/oslo.versionedobjects.egg-info/SOURCES.txt 
2017-01-18 15:11:41.000000000 +0100
@@ -53,4 +53,11 @@
 oslo_versionedobjects/tests/test_exception.py
 oslo_versionedobjects/tests/test_fields.py
 oslo_versionedobjects/tests/test_fixture.py
-oslo_versionedobjects/tests/test_objects.py
\ No newline at end of file
+oslo_versionedobjects/tests/test_objects.py
+releasenotes/notes/add-reno-996dd44974d53238.yaml
+releasenotes/source/conf.py
+releasenotes/source/index.rst
+releasenotes/source/unreleased.rst
+releasenotes/source/_static/.placeholder
+releasenotes/source/_templates/.placeholder
+tools/tox_install.sh
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.versionedobjects-1.17.0/oslo.versionedobjects.egg-info/pbr.json 
new/oslo.versionedobjects-1.21.0/oslo.versionedobjects.egg-info/pbr.json
--- old/oslo.versionedobjects-1.17.0/oslo.versionedobjects.egg-info/pbr.json    
2016-08-25 14:02:00.000000000 +0200
+++ new/oslo.versionedobjects-1.21.0/oslo.versionedobjects.egg-info/pbr.json    
2017-01-18 15:11:40.000000000 +0100
@@ -1 +1 @@
-{"is_release": true, "git_version": "181e16a"}
\ No newline at end of file
+{"is_release": true, "git_version": "1d19324"}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.versionedobjects-1.17.0/oslo.versionedobjects.egg-info/requires.txt 
new/oslo.versionedobjects-1.21.0/oslo.versionedobjects.egg-info/requires.txt
--- 
old/oslo.versionedobjects-1.17.0/oslo.versionedobjects.egg-info/requires.txt    
    2016-08-25 14:02:00.000000000 +0200
+++ 
new/oslo.versionedobjects-1.21.0/oslo.versionedobjects.egg-info/requires.txt    
    2017-01-18 15:11:40.000000000 +0100
@@ -1,15 +1,15 @@
 six>=1.9.0
 oslo.concurrency>=3.8.0
-oslo.config>=3.14.0
-oslo.context>=2.6.0
-oslo.messaging>=5.2.0
+oslo.config!=3.18.0,>=3.14.0
+oslo.context>=2.9.0
+oslo.messaging>=5.14.0
 oslo.serialization>=1.10.0
-oslo.utils>=3.16.0
+oslo.utils>=3.18.0
 iso8601>=0.1.11
-oslo.log>=1.14.0
+oslo.log>=3.11.0
 oslo.i18n>=2.1.0
-WebOb>=1.2.3
-netaddr!=0.7.16,>=0.7.12
+WebOb>=1.6.0
+netaddr!=0.7.16,>=0.7.13
 
 [fixtures]
 mock>=2.0 # BSD
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.versionedobjects-1.17.0/oslo_versionedobjects/_utils.py 
new/oslo.versionedobjects-1.21.0/oslo_versionedobjects/_utils.py
--- old/oslo.versionedobjects-1.17.0/oslo_versionedobjects/_utils.py    
2016-08-25 14:00:20.000000000 +0200
+++ new/oslo.versionedobjects-1.21.0/oslo_versionedobjects/_utils.py    
2017-01-18 15:09:53.000000000 +0100
@@ -17,7 +17,7 @@
 
 """Utilities and helper functions."""
 
-# ISO 8601 extended time format with microseconds
+# ISO 8601 extended time format without microseconds
 _ISO8601_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S'
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.versionedobjects-1.17.0/oslo_versionedobjects/base.py 
new/oslo.versionedobjects-1.21.0/oslo_versionedobjects/base.py
--- old/oslo.versionedobjects-1.17.0/oslo_versionedobjects/base.py      
2016-08-25 14:00:21.000000000 +0200
+++ new/oslo.versionedobjects-1.21.0/oslo_versionedobjects/base.py      
2017-01-18 15:09:53.000000000 +0100
@@ -56,7 +56,7 @@
         for name, field in supercls.fields.items():
             if name not in cls.fields:
                 cls.fields[name] = field
-    for name, field in six.iteritems(cls.fields):
+    for name, field in cls.fields.items():
         if not isinstance(field, obj_fields.Field):
             raise exception.ObjectFieldInvalid(
                 field=name, objname=cls.obj_name())
@@ -208,7 +208,7 @@
         if self.indirection_api:
             updates, result = self.indirection_api.object_action(
                 ctxt, self, fn.__name__, args, kwargs)
-            for key, value in six.iteritems(updates):
+            for key, value in updates.items():
                 if key in self.fields:
                     field = self.fields[key]
                     # NOTE(ndipanov): Since VersionedObjectSerializer will have
@@ -327,45 +327,11 @@
     @classmethod
     def to_json_schema(cls):
         obj_name = cls.obj_name()
-        field_schemas = {key: field.get_schema()
-                         for key, field in cls.fields.items()}
-        required_fields = [name for name, schema in
-                           sorted(field_schemas.items())]
-        namespace_key = cls._obj_primitive_key('namespace')
-        name_key = cls._obj_primitive_key('name')
-        version_key = cls._obj_primitive_key('version')
-        data_key = cls._obj_primitive_key('data')
-        changes_key = cls._obj_primitive_key('changes')
-
         schema = {
             '$schema': 'http://json-schema.org/draft-04/schema#',
             'title': obj_name,
-            'type': 'object',
-            'properties': {
-                namespace_key: {
-                    'type': 'string'
-                },
-                name_key: {
-                    'type': 'string'
-                },
-                version_key: {
-                    'type': 'string'
-                },
-                changes_key: {
-                    'type': 'array',
-                    'items': {
-                        'type': 'string'
-                    }
-                },
-                data_key: {
-                    'type': 'object',
-                    'description': 'fields of %s' % (obj_name),
-                    'properties': field_schemas,
-                    'required': required_fields
-                },
-            },
-            'required': [namespace_key, name_key, version_key, data_key]
         }
+        schema.update(obj_fields.Object(obj_name).get_schema())
         return schema
 
     @classmethod
@@ -458,6 +424,11 @@
         # of issues by copying only our field data.
 
         nobj = self.__class__()
+
+        # NOTE(sskripnick): we should save newly created object into mem
+        # to let deepcopy know which branches are already created.
+        # See launchpad bug #1602314 for more details
+        memo[id(self)] = nobj
         nobj._context = self._context
         for name in self.fields:
             if self.obj_attr_is_set(name):
@@ -880,6 +851,28 @@
                 changes.add('objects')
         return changes
 
+    def __add__(self, other):
+        # Handling arbitrary fields may not make sense if those fields are not
+        # all concatenatable. Only concatenate if the base 'objects' field is
+        # the only one and the classes match.
+        if (self.__class__ == other.__class__ and
+                list(self.__class__.fields.keys()) == ['objects']):
+            return self.__class__(objects=self.objects + other.objects)
+        else:
+            raise TypeError("List Objects should be of the same type and only "
+                            "have an 'objects' field")
+
+    def __radd__(self, other):
+        if (self.__class__ == other.__class__ and
+                list(self.__class__.fields.keys()) == ['objects']):
+            # This should never be run in practice. If the above condition is
+            # met then __add__ would have been run.
+            raise NotImplementedError('__radd__ is not implemented for '
+                                      'objects of the same type')
+        else:
+            raise TypeError("List Objects should be of the same type and only "
+                            "have an 'objects' field")
+
 
 class VersionedObjectSerializer(messaging.NoOpSerializer):
     """A VersionedObject-aware Serializer.
@@ -940,7 +933,7 @@
         iterable = values.__class__
         if issubclass(iterable, dict):
             return iterable([(k, action_fn(context, v))
-                             for k, v in six.iteritems(values)])
+                             for k, v in values.items()])
         else:
             # NOTE(danms, gibi) A set can't have an unhashable value inside,
             # such as a dict. Convert the set to list, which is fine, since we
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.versionedobjects-1.17.0/oslo_versionedobjects/fields.py 
new/oslo.versionedobjects-1.21.0/oslo_versionedobjects/fields.py
--- old/oslo.versionedobjects-1.17.0/oslo_versionedobjects/fields.py    
2016-08-25 14:00:21.000000000 +0200
+++ new/oslo.versionedobjects-1.21.0/oslo_versionedobjects/fields.py    
2017-01-18 15:09:53.000000000 +0100
@@ -324,13 +324,24 @@
         return super(Enum, self).stringify(value)
 
     def get_schema(self):
-        return {'enum': self._valid_values}
+        schema = super(Enum, self).get_schema()
+        schema['enum'] = self._valid_values
+        return schema
 
 
-class UUID(FieldType):
+class StringPattern(FieldType):
+    def get_schema(self):
+        if hasattr(self, "PATTERN"):
+            return {'type': ['string'], 'pattern': self.PATTERN}
+        else:
+            msg = _("%s has no pattern") % self.__class__.__name__
+            raise AttributeError(msg)
+
+
+class UUID(StringPattern):
 
-    _PATTERN = (r'^[a-fA-F0-9]{8}-?[a-fA-F0-9]{4}-?[a-fA-F0-9]{4}-?[a-fA-F0-9]'
-                r'{4}-?[a-fA-F0-9]{12}$')
+    PATTERN = (r'^[a-fA-F0-9]{8}-?[a-fA-F0-9]{4}-?[a-fA-F0-9]{4}-?[a-fA-F0-9]'
+               r'{4}-?[a-fA-F0-9]{12}$')
 
     @staticmethod
     def coerce(obj, attr, value):
@@ -353,14 +364,11 @@
 
             return str(value)
 
-    def get_schema(self):
-        return {'type': ['string'], 'pattern': self._PATTERN}
-
 
-class MACAddress(FieldType):
+class MACAddress(StringPattern):
 
-    _PATTERN = r'^[0-9a-f]{2}(:[0-9a-f]{2}){5}$'
-    _REGEX = re.compile(_PATTERN)
+    PATTERN = r'^[0-9a-f]{2}(:[0-9a-f]{2}){5}$'
+    _REGEX = re.compile(PATTERN)
 
     @staticmethod
     def coerce(obj, attr, value):
@@ -370,14 +378,11 @@
                 return lowered
         raise ValueError(_LE("Malformed MAC %s"), value)
 
-    def get_schema(self):
-        return {'type': ['string'], 'pattern': self._PATTERN}
-
 
-class PCIAddress(FieldType):
+class PCIAddress(StringPattern):
 
-    _PATTERN = r'^[0-9a-f]{4}:[0-9a-f]{2}:[0-1][0-9a-f].[0-7]$'
-    _REGEX = re.compile(_PATTERN)
+    PATTERN = r'^[0-9a-f]{4}:[0-9a-f]{2}:[0-1][0-9a-f].[0-7]$'
+    _REGEX = re.compile(PATTERN)
 
     @staticmethod
     def coerce(obj, attr, value):
@@ -387,9 +392,6 @@
                 return newvalue
         raise ValueError(_LE("Malformed PCI address %s"), value)
 
-    def get_schema(self):
-        return {'type': ['string'], 'pattern': self._PATTERN}
-
 
 class Integer(FieldType):
     @staticmethod
@@ -408,6 +410,9 @@
             raise ValueError(_('Value must be >= 0 for field %s') % attr)
         return v
 
+    def get_schema(self):
+        return {'type': ['integer'], 'minimum': 0}
+
 
 class Float(FieldType):
     def coerce(self, obj, attr, value):
@@ -425,6 +430,9 @@
             raise ValueError(_('Value must be >= 0 for field %s') % attr)
         return v
 
+    def get_schema(self):
+        return {'type': ['number'], 'minimum': 0}
+
 
 class Boolean(FieldType):
     @staticmethod
@@ -480,7 +488,7 @@
         return _utils.isotime(value)
 
 
-class IPAddress(FieldType):
+class IPAddress(StringPattern):
     @staticmethod
     def coerce(obj, attr, value):
         try:
@@ -535,7 +543,8 @@
         return result
 
     def get_schema(self):
-        return {'type': ['string'], 'format': 'ipv6'}
+        return {'oneOf': [IPV4Address().get_schema(),
+                          IPV6Address().get_schema()]}
 
 
 class IPNetwork(IPAddress):
@@ -549,9 +558,9 @@
 
 class IPV4Network(IPNetwork):
 
-    _PATTERN = (r'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-'
-                r'9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2]['
-                r'0-9]|3[0-2]))$')
+    PATTERN = (r'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-'
+               r'9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2]['
+               r'0-9]|3[0-2]))$')
 
     @staticmethod
     def coerce(obj, attr, value):
@@ -560,15 +569,12 @@
         except netaddr.AddrFormatError as e:
             raise ValueError(six.text_type(e))
 
-    def get_schema(self):
-        return {'type': ['string'], 'pattern': self._PATTERN}
-
 
 class IPV6Network(IPNetwork):
 
     def __init__(self, *args, **kwargs):
         super(IPV6Network, self).__init__(*args, **kwargs)
-        self._PATTERN = self._create_pattern()
+        self.PATTERN = self._create_pattern()
 
     @staticmethod
     def coerce(obj, attr, value):
@@ -617,9 +623,6 @@
             '(\/(d|dd|1[0-1]d|12[0-8]))$'
             )
 
-    def get_schema(self):
-        return {'type': ['string'], 'pattern': self._PATTERN}
-
 
 class CompoundFieldType(FieldType):
     def __init__(self, element_type, **field_args):
@@ -682,7 +685,8 @@
                       for key, val in sorted(value.items())]))
 
     def get_schema(self):
-        return {'type': ['object']}
+        return {'type': ['object'],
+                'additionalProperties': self._element_type.get_schema()}
 
 
 class DictProxyField(object):
@@ -707,14 +711,14 @@
         if getattr(obj, self._fld_name) is None:
             return
         return {self._key_type(k): v
-                for k, v in six.iteritems(getattr(obj, self._fld_name))}
+                for k, v in getattr(obj, self._fld_name).items()}
 
     def __set__(self, obj, val):
         if val is None:
             setattr(obj, self._fld_name, val)
         else:
             setattr(obj, self._fld_name,
-                    {six.text_type(k): v for k, v in six.iteritems(val)})
+                    {six.text_type(k): v for k, v in val.items()})
 
 
 class Set(CompoundFieldType):
@@ -819,6 +823,54 @@
 
         return '%s%s' % (self._obj_name, ident)
 
+    def get_schema(self):
+        from oslo_versionedobjects import base as obj_base
+        obj_classes = obj_base.VersionedObjectRegistry.obj_classes()
+        if self._obj_name in obj_classes:
+            cls = obj_classes[self._obj_name][0]
+            namespace_key = cls._obj_primitive_key('namespace')
+            name_key = cls._obj_primitive_key('name')
+            version_key = cls._obj_primitive_key('version')
+            data_key = cls._obj_primitive_key('data')
+            changes_key = cls._obj_primitive_key('changes')
+            field_schemas = {key: field.get_schema()
+                             for key, field in cls.fields.items()}
+            required_fields = [key for key, field in sorted(cls.fields.items())
+                               if not field.nullable]
+            schema = {
+                'type': 'object',
+                'properties': {
+                    namespace_key: {
+                        'type': 'string'
+                    },
+                    name_key: {
+                        'type': 'string'
+                    },
+                    version_key: {
+                        'type': 'string'
+                    },
+                    changes_key: {
+                        'type': 'array',
+                        'items': {
+                            'type': 'string'
+                        }
+                    },
+                    data_key: {
+                        'type': 'object',
+                        'description': 'fields of %s' % self._obj_name,
+                        'properties': field_schemas,
+                    },
+                },
+                'required': [namespace_key, name_key, version_key, data_key]
+            }
+
+            if required_fields:
+                schema['properties'][data_key]['required'] = required_fields
+
+            return schema
+        else:
+            raise exception.UnsupportedObjectError(objtype=self._obj_name)
+
 
 class AutoTypedField(Field):
     AUTO_TYPE = None
@@ -882,7 +934,7 @@
 
     This class allows for anonymous enum types to be
     declared, simply by passing in a list of valid values
-    to its constructor. It is generally preferrable though,
+    to its constructor. It is generally preferable though,
     to create an explicit named enum type by sub-classing
     the BaseEnumField type directly.
     '''
@@ -1214,7 +1266,7 @@
 
     def _coerce_dict(self, d):
         res = {}
-        for key, element in six.iteritems(d):
+        for key, element in d.items():
             res[key] = self._coerce_item(key, element)
         return res
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.versionedobjects-1.17.0/oslo_versionedobjects/fixture.py 
new/oslo.versionedobjects-1.21.0/oslo_versionedobjects/fixture.py
--- old/oslo.versionedobjects-1.17.0/oslo_versionedobjects/fixture.py   
2016-08-25 14:00:20.000000000 +0200
+++ new/oslo.versionedobjects-1.21.0/oslo_versionedobjects/fixture.py   
2017-01-18 15:09:53.000000000 +0100
@@ -124,7 +124,7 @@
         kwargs = dict(
             [(argname, self._ser.deserialize_entity(
                 context, self._ser.serialize_entity(context, arg)))
-             for argname, arg in six.iteritems(kwargs)])
+             for argname, arg in kwargs.items()])
         return args, kwargs
 
     def object_action(self, context, objinst, objmethod, args, kwargs):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.versionedobjects-1.17.0/oslo_versionedobjects/tests/test_fields.py 
new/oslo.versionedobjects-1.21.0/oslo_versionedobjects/tests/test_fields.py
--- old/oslo.versionedobjects-1.17.0/oslo_versionedobjects/tests/test_fields.py 
2016-08-25 14:00:20.000000000 +0200
+++ new/oslo.versionedobjects-1.21.0/oslo_versionedobjects/tests/test_fields.py 
2017-01-18 15:09:53.000000000 +0100
@@ -302,7 +302,6 @@
         self.assertEqual(['string'], schema['type'])
         self.assertEqual(False, schema['readonly'])
         pattern = schema['pattern']
-        print(self.coerce_good_values)
         for _, valid_val in self.coerce_good_values[:4]:
             self.assertRegex(valid_val, pattern)
         invalid_vals = [x for x in self.coerce_bad_values if type(x) == 'str']
@@ -360,11 +359,11 @@
         self.assertRaises(ValueError, self.field.stringify, '123')
 
     def test_fieldtype_get_schema(self):
-        self.assertEqual({'enum': ["foo", "bar", 1, True]},
+        self.assertEqual({'type': ['string'], 'enum': ["foo", "bar", 1, True]},
                          self.field._type.get_schema())
 
     def test_get_schema(self):
-        self.assertEqual({'enum': ["foo", "bar", 1, True],
+        self.assertEqual({'type': ['string'], 'enum': ["foo", "bar", 1, True],
                           'readonly': False}, self.field.get_schema())
 
     def test_fingerprint(self):
@@ -487,6 +486,10 @@
         self.to_primitive_values = self.coerce_good_values[0:1]
         self.from_primitive_values = self.coerce_good_values[0:1]
 
+    def test_get_schema(self):
+        self.assertEqual({'type': ['integer'], 'readonly': False,
+                          'minimum': 0}, self.field.get_schema())
+
 
 class TestFloat(TestField):
     def setUp(self):
@@ -514,6 +517,10 @@
         self.to_primitive_values = self.coerce_good_values[0:1]
         self.from_primitive_values = self.coerce_good_values[0:1]
 
+    def test_get_schema(self):
+        self.assertEqual({'type': ['number'], 'readonly': False,
+                          'minimum': 0}, self.field.get_schema())
+
 
 class TestBoolean(TestField):
     def setUp(self):
@@ -611,7 +618,10 @@
         self.assertEqual("{key=val}", self.field.stringify({'key': 'val'}))
 
     def test_get_schema(self):
-        self.assertEqual({'type': ['object'], 'readonly': False},
+        self.assertEqual({'type': ['object'],
+                          'additionalProperties': {'readonly': False,
+                                                   'type': ['foo']},
+                          'readonly': False},
                          self.field.get_schema())
 
 
@@ -1010,6 +1020,31 @@
         self.assertEqual('An object of type TestableObject is required '
                          'in field attr, not a list', six.text_type(ex))
 
+    def test_get_schema(self):
+        self.assertEqual(
+            {
+                'properties': {
+                    'versioned_object.changes':
+                        {'items': {'type': 'string'}, 'type': 'array'},
+                    'versioned_object.data': {
+                        'description': 'fields of TestableObject',
+                        'properties':
+                            {'uuid': {'readonly': False, 'type': ['string']}},
+                        'required': ['uuid'],
+                        'type': 'object'},
+                    'versioned_object.name': {'type': 'string'},
+                    'versioned_object.namespace': {'type': 'string'},
+                    'versioned_object.version': {'type': 'string'}
+                },
+                'readonly': False,
+                'required': ['versioned_object.namespace',
+                             'versioned_object.name',
+                             'versioned_object.version',
+                             'versioned_object.data'],
+                'type': 'object'
+            },
+            self.field.get_schema())
+
 
 class TestIPAddress(TestField):
     def setUp(self):
@@ -1055,8 +1090,7 @@
                                     netaddr.IPAddress('::1'))]
         self.coerce_bad_values = ['1.2', 'foo', '1.2.3.4']
         self.to_primitive_values = [(netaddr.IPAddress('::1'), '::1')]
-        self.from_primitive_values = [('::1',
-                                       netaddr.IPAddress('::1'))]
+        self.from_primitive_values = [('::1', netaddr.IPAddress('::1'))]
 
     def test_get_schema(self):
         self.assertEqual({'type': ['string'], 'readonly': False,
@@ -1085,6 +1119,11 @@
                                       ('1.2.3.4',
                                        netaddr.IPAddress('1.2.3.4'))]
 
+    def test_get_schema(self):
+        self.assertEqual({'oneOf': [{'format': 'ipv4', 'type': ['string']},
+                                    {'format': 'ipv6', 'type': ['string']}]},
+                         self.field.get_schema())
+
 
 class TestIPNetwork(TestField):
     def setUp(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.versionedobjects-1.17.0/oslo_versionedobjects/tests/test_objects.py 
new/oslo.versionedobjects-1.21.0/oslo_versionedobjects/tests/test_objects.py
--- 
old/oslo.versionedobjects-1.17.0/oslo_versionedobjects/tests/test_objects.py    
    2016-08-25 14:00:21.000000000 +0200
+++ 
new/oslo.versionedobjects-1.21.0/oslo_versionedobjects/tests/test_objects.py    
    2017-01-18 15:09:53.000000000 +0100
@@ -14,6 +14,7 @@
 
 import copy
 import datetime
+import jsonschema
 import logging
 import pytz
 import six
@@ -2065,34 +2066,25 @@
 
 
 class TestSchemaGeneration(test.TestCase):
-    class FakeFieldType(fields.FieldType):
-        pass
-
-    def setUp(self):
-        super(TestSchemaGeneration, self).setUp()
-
-        self.nonNullableField = fields.Field(self.FakeFieldType)
-        self.nullableField = fields.Field(self.FakeFieldType)
-
-        class TestObject(base.VersionedObject):
-            fields = {'foo': self.nonNullableField,
-                      'bar': self.nullableField}
-
-        self.test_class = TestObject
+    @base.VersionedObjectRegistry.register
+    class FakeObject(base.VersionedObject):
+        fields = {
+            'a_boolean': fields.BooleanField(nullable=True),
+        }
 
-        self.nonNullableField.get_schema = \
-            mock.Mock(return_value={'type': ['fake']})
-        self.nullableField.get_schema = \
-            mock.Mock(return_value={'type': ['fake', 'null']})
-        self.test_class.obj_name = mock.Mock(return_value='TestObject')
+    @base.VersionedObjectRegistry.register
+    class FakeComplexObject(base.VersionedObject):
+        fields = {
+            'a_dict': fields.DictOfListOfStringsField(),
+            'an_obj': fields.ObjectField('FakeObject'),
+            'list_of_objs': fields.ListOfObjectsField('FakeObject'),
+        }
 
     def test_to_json_schema(self):
-        schema = self.test_class.to_json_schema()
-        self.nonNullableField.get_schema.assert_called_once_with()
-        self.nullableField.get_schema.assert_called_once_with()
+        schema = self.FakeObject.to_json_schema()
         self.assertEqual({
             '$schema': 'http://json-schema.org/draft-04/schema#',
-            'title': 'TestObject',
+            'title': 'FakeObject',
             'type': 'object',
             'properties': {
                 'versioned_object.namespace': {
@@ -2112,18 +2104,113 @@
                 },
                 'versioned_object.data': {
                     'type': 'object',
-                    'description': 'fields of TestObject',
+                    'description': 'fields of FakeObject',
                     'properties': {
-                        'foo': {'type': ['fake']},
-                        'bar': {'type': ['fake', 'null']}
+                        'a_boolean': {
+                            'readonly': False,
+                            'type': ['boolean', 'null']},
                     },
-                    'required': ['bar', 'foo'],
                 },
             },
             'required': ['versioned_object.namespace', 'versioned_object.name',
                          'versioned_object.version', 'versioned_object.data']
         }, schema)
 
+        jsonschema.validate(self.FakeObject(a_boolean=True).obj_to_primitive(),
+                            self.FakeObject.to_json_schema())
+
+    def test_to_json_schema_complex_object(self):
+        schema = self.FakeComplexObject.to_json_schema()
+        expected_schema = {
+            '$schema': 'http://json-schema.org/draft-04/schema#',
+            'properties': {
+                'versioned_object.changes':
+                    {'items': {'type': 'string'}, 'type': 'array'},
+                'versioned_object.data': {
+                    'description': 'fields of FakeComplexObject',
+                    'properties': {
+                        'a_dict': {
+                            'readonly': False,
+                            'type': ['object'],
+                            'additionalProperties': {
+                                'type': ['array'],
+                                'readonly': False,
+                                'items': {
+                                    'type': ['string'],
+                                    'readonly': False}}},
+                        'an_obj': {
+                            'properties': {
+                                'versioned_object.changes':
+                                    {'items': {'type': 'string'},
+                                     'type': 'array'},
+                                'versioned_object.data': {
+                                    'description': 'fields of FakeObject',
+                                    'properties':
+                                        {'a_boolean': {'readonly': False,
+                                         'type': ['boolean', 'null']}},
+                                    'type': 'object'},
+                                'versioned_object.name': {'type': 'string'},
+                                'versioned_object.namespace':
+                                    {'type': 'string'},
+                                'versioned_object.version':
+                                    {'type': 'string'}},
+                                'readonly': False,
+                                'required': ['versioned_object.namespace',
+                                             'versioned_object.name',
+                                             'versioned_object.version',
+                                             'versioned_object.data'],
+                                'type': 'object'},
+                        'list_of_objs': {
+                            'items': {
+                                'properties': {
+                                    'versioned_object.changes':
+                                        {'items': {'type': 'string'},
+                                         'type': 'array'},
+                                    'versioned_object.data': {
+                                        'description': 'fields of FakeObject',
+                                        'properties': {
+                                            'a_boolean': {
+                                                'readonly': False,
+                                                'type': ['boolean', 'null']}},
+                                            'type': 'object'},
+                                    'versioned_object.name':
+                                        {'type': 'string'},
+                                    'versioned_object.namespace':
+                                        {'type': 'string'},
+                                    'versioned_object.version':
+                                        {'type': 'string'}},
+                                'readonly': False,
+                                'required': ['versioned_object.namespace',
+                                             'versioned_object.name',
+                                             'versioned_object.version',
+                                             'versioned_object.data'],
+                                'type': 'object'},
+                            'readonly': False,
+                            'type': ['array']}},
+                    'required': ['a_dict', 'an_obj', 'list_of_objs'],
+                    'type': 'object'},
+                'versioned_object.name': {'type': 'string'},
+                'versioned_object.namespace': {'type': 'string'},
+                'versioned_object.version': {'type': 'string'}},
+            'required': ['versioned_object.namespace',
+                         'versioned_object.name',
+                         'versioned_object.version',
+                         'versioned_object.data'],
+            'title': 'FakeComplexObject',
+            'type': 'object'}
+        self.assertEqual(expected_schema, schema)
+
+        fake_obj = self.FakeComplexObject(
+            a_dict={'key1': ['foo', 'bar'],
+                    'key2': ['bar', 'baz']},
+            an_obj=self.FakeObject(a_boolean=True),
+            list_of_objs=[self.FakeObject(a_boolean=False),
+                          self.FakeObject(a_boolean=True),
+                          self.FakeObject(a_boolean=False)])
+
+        primitives = fake_obj.obj_to_primitive()
+        jsonschema.validate(primitives, schema)
+
 
 class TestNamespaceCompatibility(test.TestCase):
     def setUp(self):
@@ -2251,3 +2338,92 @@
                           'TestChild': '2.34',
                           'TestChildTwo': '4.56'},
                          tree)
+
+
+class TestListObjectConcat(test.TestCase):
+    def test_list_object_concat(self):
+        @base.VersionedObjectRegistry.register_if(False)
+        class MyList(base.ObjectListBase, base.VersionedObject):
+            fields = {'objects': fields.ListOfObjectsField('MyOwnedObject')}
+
+        values = [1, 2, 42]
+
+        list1 = MyList(objects=[MyOwnedObject(baz=values[0]),
+                                MyOwnedObject(baz=values[1])])
+        list2 = MyList(objects=[MyOwnedObject(baz=values[2])])
+
+        concat_list = list1 + list2
+        for idx, obj in enumerate(concat_list):
+            self.assertEqual(values[idx], obj.baz)
+
+        # Assert that the original lists are unmodified
+        self.assertEqual(2, len(list1.objects))
+        self.assertEqual(1, list1.objects[0].baz)
+        self.assertEqual(2, list1.objects[1].baz)
+        self.assertEqual(1, len(list2.objects))
+        self.assertEqual(42, list2.objects[0].baz)
+
+    def test_list_object_concat_fails_different_objects(self):
+        @base.VersionedObjectRegistry.register_if(False)
+        class MyList(base.ObjectListBase, base.VersionedObject):
+            fields = {'objects': fields.ListOfObjectsField('MyOwnedObject')}
+
+        @base.VersionedObjectRegistry.register_if(False)
+        class MyList2(base.ObjectListBase, base.VersionedObject):
+            fields = {'objects': fields.ListOfObjectsField('MyOwnedObject')}
+
+        list1 = MyList(objects=[MyOwnedObject(baz=1)])
+        list2 = MyList2(objects=[MyOwnedObject(baz=2)])
+
+        def add(x, y):
+            return x + y
+
+        self.assertRaises(TypeError, add, list1, list2)
+        # Assert that the original lists are unmodified
+        self.assertEqual(1, len(list1.objects))
+        self.assertEqual(1, len(list2.objects))
+        self.assertEqual(1, list1.objects[0].baz)
+        self.assertEqual(2, list2.objects[0].baz)
+
+    def test_list_object_concat_fails_extra_fields(self):
+        @base.VersionedObjectRegistry.register_if(False)
+        class MyList(base.ObjectListBase, base.VersionedObject):
+            fields = {'objects': fields.ListOfObjectsField('MyOwnedObject'),
+                      'foo': fields.IntegerField(nullable=True)}
+
+        list1 = MyList(objects=[MyOwnedObject(baz=1)])
+        list2 = MyList(objects=[MyOwnedObject(baz=2)])
+
+        def add(x, y):
+            return x + y
+
+        self.assertRaises(TypeError, add, list1, list2)
+        # Assert that the original lists are unmodified
+        self.assertEqual(1, len(list1.objects))
+        self.assertEqual(1, len(list2.objects))
+        self.assertEqual(1, list1.objects[0].baz)
+        self.assertEqual(2, list2.objects[0].baz)
+
+    def test_builtin_list_add_fails(self):
+        @base.VersionedObjectRegistry.register_if(False)
+        class MyList(base.ObjectListBase, base.VersionedObject):
+            fields = {'objects': fields.ListOfObjectsField('MyOwnedObject')}
+
+        list1 = MyList(objects=[MyOwnedObject(baz=1)])
+
+        def add(obj):
+            return obj + []
+
+        self.assertRaises(TypeError, add, list1)
+
+    def test_builtin_list_radd_fails(self):
+        @base.VersionedObjectRegistry.register_if(False)
+        class MyList(base.ObjectListBase, base.VersionedObject):
+            fields = {'objects': fields.ListOfObjectsField('MyOwnedObject')}
+
+        list1 = MyList(objects=[MyOwnedObject(baz=1)])
+
+        def add(obj):
+            return [] + obj
+
+        self.assertRaises(TypeError, add, list1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.versionedobjects-1.17.0/releasenotes/notes/add-reno-996dd44974d53238.yaml
 
new/oslo.versionedobjects-1.21.0/releasenotes/notes/add-reno-996dd44974d53238.yaml
--- 
old/oslo.versionedobjects-1.17.0/releasenotes/notes/add-reno-996dd44974d53238.yaml
  1970-01-01 01:00:00.000000000 +0100
+++ 
new/oslo.versionedobjects-1.21.0/releasenotes/notes/add-reno-996dd44974d53238.yaml
  2017-01-18 15:09:53.000000000 +0100
@@ -0,0 +1,3 @@
+---
+other:
+  - Introduce reno for deployer release notes.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.versionedobjects-1.17.0/releasenotes/source/conf.py 
new/oslo.versionedobjects-1.21.0/releasenotes/source/conf.py
--- old/oslo.versionedobjects-1.17.0/releasenotes/source/conf.py        
1970-01-01 01:00:00.000000000 +0100
+++ new/oslo.versionedobjects-1.21.0/releasenotes/source/conf.py        
2017-01-18 15:09:53.000000000 +0100
@@ -0,0 +1,276 @@
+# -*- coding: utf-8 -*-
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+# sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+    'oslosphinx',
+    'reno.sphinxext',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+# source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'oslo.versionedobjects Release Notes'
+copyright = u'2016, oslo.versionedobjects Developers'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+# The full version, including alpha/beta/rc tags.
+import pkg_resources
+release = pkg_resources.get_distribution('oslo.versionedobjects').version
+# The short X.Y version.
+version = release
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+# language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+# today = ''
+# Else, today_fmt is used as the format for a strftime call.
+# today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+# default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+# add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+# add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+# show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+# modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+# keep_warnings = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+# html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+# html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+# html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+# html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+# html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+# html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+# html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+# html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+# html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+# html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+# html_additional_pages = {}
+
+# If false, no module index is generated.
+# html_domain_indices = True
+
+# If false, no index is generated.
+# html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+# html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+# html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+# html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+# html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+# html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+# html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'oslo.versionedobjectsReleaseNotesDoc'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+    # The paper size ('letterpaper' or 'a4paper').
+    # 'papersize': 'letterpaper',
+
+    # The font size ('10pt', '11pt' or '12pt').
+    # 'pointsize': '10pt',
+
+    # Additional stuff for the LaTeX preamble.
+    # 'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+    ('index', 'oslo.versionedobjectsReleaseNotes.tex',
+     u'oslo.versionedobjects Release Notes Documentation',
+     u'oslo.versionedobjects Developers', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+# latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+# latex_use_parts = False
+
+# If true, show page references after internal links.
+# latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+# latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+# latex_appendices = []
+
+# If false, no module index is generated.
+# latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'oslo.versionedobjectsReleaseNotes',
+     u'oslo.versionedobjects Release Notes Documentation',
+     [u'oslo.versionedobjects Developers'], 1)
+]
+
+# If true, show URL addresses after external links.
+# man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+    ('index', 'oslo.versionedobjectsReleaseNotes',
+     u'oslo.versionedobjects Release Notes Documentation',
+     u'oslo.versionedobjects Developers', 'oslo.versionedobjectsReleaseNotes',
+     'One line description of project.',
+     'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+# texinfo_appendices = []
+
+# If false, no module index is generated.
+# texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+# texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+# texinfo_no_detailmenu = False
+
+# -- Options for Internationalization output ------------------------------
+locale_dirs = ['locale/']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.versionedobjects-1.17.0/releasenotes/source/index.rst 
new/oslo.versionedobjects-1.21.0/releasenotes/source/index.rst
--- old/oslo.versionedobjects-1.17.0/releasenotes/source/index.rst      
1970-01-01 01:00:00.000000000 +0100
+++ new/oslo.versionedobjects-1.21.0/releasenotes/source/index.rst      
2017-01-18 15:09:53.000000000 +0100
@@ -0,0 +1,8 @@
+=====================================
+ oslo.versionedobjects Release Notes
+=====================================
+
+ .. toctree::
+    :maxdepth: 1
+
+    unreleased
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslo.versionedobjects-1.17.0/releasenotes/source/unreleased.rst 
new/oslo.versionedobjects-1.21.0/releasenotes/source/unreleased.rst
--- old/oslo.versionedobjects-1.17.0/releasenotes/source/unreleased.rst 
1970-01-01 01:00:00.000000000 +0100
+++ new/oslo.versionedobjects-1.21.0/releasenotes/source/unreleased.rst 
2017-01-18 15:09:53.000000000 +0100
@@ -0,0 +1,5 @@
+==============================
+ Current Series Release Notes
+==============================
+
+.. release-notes::
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.versionedobjects-1.17.0/requirements.txt 
new/oslo.versionedobjects-1.21.0/requirements.txt
--- old/oslo.versionedobjects-1.17.0/requirements.txt   2016-08-25 
14:00:21.000000000 +0200
+++ new/oslo.versionedobjects-1.21.0/requirements.txt   2017-01-18 
15:09:53.000000000 +0100
@@ -3,13 +3,13 @@
 # process, which may cause wedges in the gate later.
 six>=1.9.0 # MIT
 oslo.concurrency>=3.8.0 # Apache-2.0
-oslo.config>=3.14.0 # Apache-2.0
-oslo.context>=2.6.0 # Apache-2.0
-oslo.messaging>=5.2.0 # Apache-2.0
+oslo.config!=3.18.0,>=3.14.0 # Apache-2.0
+oslo.context>=2.9.0 # Apache-2.0
+oslo.messaging>=5.14.0 # Apache-2.0
 oslo.serialization>=1.10.0 # Apache-2.0
-oslo.utils>=3.16.0 # Apache-2.0
+oslo.utils>=3.18.0 # Apache-2.0
 iso8601>=0.1.11 # MIT
-oslo.log>=1.14.0 # Apache-2.0
+oslo.log>=3.11.0 # Apache-2.0
 oslo.i18n>=2.1.0 # Apache-2.0
-WebOb>=1.2.3 # MIT
-netaddr!=0.7.16,>=0.7.12 # BSD
+WebOb>=1.6.0 # MIT
+netaddr!=0.7.16,>=0.7.13 # BSD
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.versionedobjects-1.17.0/setup.cfg 
new/oslo.versionedobjects-1.21.0/setup.cfg
--- old/oslo.versionedobjects-1.17.0/setup.cfg  2016-08-25 14:02:00.000000000 
+0200
+++ new/oslo.versionedobjects-1.21.0/setup.cfg  2017-01-18 15:11:41.000000000 
+0100
@@ -5,7 +5,7 @@
        README.rst
 author = OpenStack
 author-email = [email protected]
-home-page = http://launchpad.net/oslo
+home-page = http://docs.openstack.org/developer/oslo.versionedobjects
 classifier = 
        Environment :: OpenStack
        Intended Audience :: Information Technology
@@ -63,5 +63,4 @@
 [egg_info]
 tag_build = 
 tag_date = 0
-tag_svn_revision = 0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.versionedobjects-1.17.0/test-requirements.txt 
new/oslo.versionedobjects-1.21.0/test-requirements.txt
--- old/oslo.versionedobjects-1.17.0/test-requirements.txt      2016-08-25 
14:00:20.000000000 +0200
+++ new/oslo.versionedobjects-1.21.0/test-requirements.txt      2017-01-18 
15:09:53.000000000 +0100
@@ -5,7 +5,9 @@
 oslotest>=1.10.0 # Apache-2.0
 testtools>=1.4.0 # MIT
 # These are needed for docs generation
-oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
-sphinx!=1.3b1,<1.3,>=1.2.1 # BSD
+oslosphinx>=4.7.0 # Apache-2.0
+sphinx!=1.3b1,<1.4,>=1.2.1 # BSD
 
-coverage>=3.6 # Apache-2.0
+coverage>=4.0 # Apache-2.0
+jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
+reno>=1.8.0 # Apache-2.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.versionedobjects-1.17.0/tools/tox_install.sh 
new/oslo.versionedobjects-1.21.0/tools/tox_install.sh
--- old/oslo.versionedobjects-1.17.0/tools/tox_install.sh       1970-01-01 
01:00:00.000000000 +0100
+++ new/oslo.versionedobjects-1.21.0/tools/tox_install.sh       2017-01-18 
15:09:53.000000000 +0100
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# Client constraint file contains this client version pin that is in conflict
+# with installing the client from source. We should remove the version pin in
+# the constraints file before applying it for from-source installation.
+
+CONSTRAINTS_FILE=$1
+shift 1
+
+set -e
+
+# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get
+# published to logs.openstack.org for easy debugging.
+localfile="$VIRTUAL_ENV/log/upper-constraints.txt"
+
+if [[ $CONSTRAINTS_FILE != http* ]]; then
+    CONSTRAINTS_FILE=file://$CONSTRAINTS_FILE
+fi
+# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep
+curl $CONSTRAINTS_FILE --insecure --progress-bar --output $localfile
+
+pip install -c$localfile openstack-requirements
+
+# This is the main purpose of the script: Allow local installation of
+# the current repo. It is listed in constraints file and thus any
+# install will be constrained and we need to unconstrain it.
+edit-constraints $localfile -- $CLIENT_NAME
+
+pip install -c$localfile -U $*
+exit $?
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslo.versionedobjects-1.17.0/tox.ini 
new/oslo.versionedobjects-1.21.0/tox.ini
--- old/oslo.versionedobjects-1.17.0/tox.ini    2016-08-25 14:00:20.000000000 
+0200
+++ new/oslo.versionedobjects-1.21.0/tox.ini    2017-01-18 15:09:53.000000000 
+0100
@@ -1,8 +1,13 @@
 [tox]
-minversion = 1.6
+minversion = 2.0
 envlist = py35,py34,py27,pypy,pep8
 
 [testenv]
+setenv =
+    VIRTUAL_ENV={envdir}
+    BRANCH_NAME=master
+    CLIENT_NAME=oslo.versionedobjects
+install_command = {toxinidir}/tools/tox_install.sh 
{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
 {opts} {packages}
 deps = .[fixtures]
        -r{toxinidir}/test-requirements.txt
 commands = python setup.py testr --slowest --testr-args='{posargs}'
@@ -37,3 +42,6 @@
 # of the requirements.txt files
 deps = pip_missing_reqs
 commands = pip-missing-reqs -d --ignore-module=oslo_versionedobjects* 
--ignore-module=pkg_resources --ignore-file=oslo_versionedobjects/test.py 
--ignore-file=oslo_versionedobjects/tests/* oslo_versionedobjects
+
+[testenv:releasenotes]
+commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html 
releasenotes/source releasenotes/build/html


Reply via email to