Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-atom for openSUSE:Factory 
checked in at 2023-10-05 20:04:59
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-atom (Old)
 and      /work/SRC/openSUSE:Factory/.python-atom.new.28202 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-atom"

Thu Oct  5 20:04:59 2023 rev:12 rq:1115791 version:0.10.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-atom/python-atom.changes  2023-06-01 
17:20:05.070361018 +0200
+++ /work/SRC/openSUSE:Factory/.python-atom.new.28202/python-atom.changes       
2023-10-05 20:06:12.169323573 +0200
@@ -1,0 +2,9 @@
+Thu Oct  5 09:46:45 UTC 2023 - Dirk Müller <[email protected]>
+
+- update to 0.10.3:
+  * fix a an issue when using add_member to override an existing
+    membe
+  * fix a memory leak caused by Dict, Defaultdict and Set members
+  * add support for Python 3.12 PR #200
+
+-------------------------------------------------------------------

Old:
----
  atom-0.10.0.tar.gz

New:
----
  atom-0.10.3.tar.gz

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

Other differences:
------------------
++++++ python-atom.spec ++++++
--- /var/tmp/diff_new_pack.nVToNP/_old  2023-10-05 20:06:13.257362881 +0200
+++ /var/tmp/diff_new_pack.nVToNP/_new  2023-10-05 20:06:13.257362881 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-atom
-Version:        0.10.0
+Version:        0.10.3
 Release:        0
 Summary:        Memory efficient Python objects
 License:        BSD-3-Clause

++++++ atom-0.10.0.tar.gz -> atom-0.10.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/.github/workflows/ci.yml 
new/atom-0.10.3/.github/workflows/ci.yml
--- old/atom-0.10.0/.github/workflows/ci.yml    2023-05-05 10:02:54.000000000 
+0200
+++ new/atom-0.10.3/.github/workflows/ci.yml    2023-10-04 10:36:05.000000000 
+0200
@@ -22,9 +22,9 @@
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: ['3.10']
+        python-version: ['3.11']
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - name: Set up Python ${{ matrix.python-version }}
         uses: actions/setup-python@v4
         with:
@@ -65,7 +65,7 @@
       matrix:
         python-version: ['3.8', '3.9']
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - name: Get history and tags for SCM versioning to work
         run: |
           git fetch --prune --unshallow
@@ -97,9 +97,9 @@
     strategy:
       matrix:
         os: [ubuntu-latest, windows-latest, macos-latest]
-        python-version: ['3.8', '3.9', '3.10', '3.11']
+        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12-dev']
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - name: Get history and tags for SCM versioning to work
         run: |
           git fetch --prune --unshallow
@@ -120,7 +120,7 @@
           CPPFLAGS: --coverage
         # Build extensions manually to allow getting C coverage data
         run: |
-          python setup.py develop
+          pip install -e .
       - name: Test with pytest
         # XXX Disabled warnings check ( -W error) to be able to test on 3.11
         # (pyparsing deprecation)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/.github/workflows/docs.yml 
new/atom-0.10.3/.github/workflows/docs.yml
--- old/atom-0.10.0/.github/workflows/docs.yml  2023-05-05 10:02:54.000000000 
+0200
+++ new/atom-0.10.3/.github/workflows/docs.yml  2023-10-04 10:36:05.000000000 
+0200
@@ -21,7 +21,7 @@
     name: Docs building
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - name: Get history and tags for SCM versioning to work
         run: |
           git fetch --prune --unshallow
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/.github/workflows/release.yml 
new/atom-0.10.3/.github/workflows/release.yml
--- old/atom-0.10.0/.github/workflows/release.yml       2023-05-05 
10:02:54.000000000 +0200
+++ new/atom-0.10.3/.github/workflows/release.yml       2023-10-04 
10:36:05.000000000 +0200
@@ -13,7 +13,7 @@
     runs-on: ubuntu-latest
     steps:
       - name: Checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
       - name: Get history and tags for SCM versioning to work
         run: |
           git fetch --prune --unshallow
@@ -45,10 +45,10 @@
     strategy:
       matrix:
         os: [windows-latest, ubuntu-latest, macos-latest]
-        python: [38, 39, 310, 311]
+        python: [38, 39, 310, 311, 312]
     steps:
       - name: Checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
       - name: Get history and tags for SCM versioning to work
         run: |
           git fetch --prune --unshallow
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/PKG-INFO new/atom-0.10.3/PKG-INFO
--- old/atom-0.10.0/PKG-INFO    2023-05-05 10:03:22.152537300 +0200
+++ new/atom-0.10.3/PKG-INFO    2023-10-04 10:36:34.202414300 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: atom
-Version: 0.10.0
+Version: 0.10.3
 Summary: Memory efficient Python objects
 Author-email: The Nucleic Development Team <[email protected]>
 Maintainer-email: "Matthieu C. Dartiailh" <[email protected]>
@@ -98,6 +98,7 @@
 Requires-Python: >=3.8
 Description-Content-Type: text/x-rst
 License-File: LICENSE
+Requires-Dist: typing_extensions; python_version < "3.11"
 
 Welcome to Atom
 ===============
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/atom/meta/atom_meta.py 
new/atom-0.10.3/atom/meta/atom_meta.py
--- old/atom-0.10.0/atom/meta/atom_meta.py      2023-05-05 10:02:54.000000000 
+0200
+++ new/atom-0.10.3/atom/meta/atom_meta.py      2023-10-04 10:36:05.000000000 
+0200
@@ -55,8 +55,8 @@
     """Add or override a member after the class creation."""
     existing = cls.__atom_members__.get(name)
     if existing is not None:
-        member.set_index(member.index)
-        member.copy_static_observers(member)
+        member.set_index(existing.index)
+        member.copy_static_observers(existing)
     else:
         member.set_index(len(cls.__atom_members__))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/atom/src/atomdict.cpp 
new/atom-0.10.3/atom/src/atomdict.cpp
--- old/atom-0.10.0/atom/src/atomdict.cpp       2023-05-05 10:02:54.000000000 
+0200
+++ new/atom-0.10.3/atom/src/atomdict.cpp       2023-10-04 10:36:05.000000000 
+0200
@@ -114,8 +114,11 @@
 
 void AtomDict_dealloc( AtomDict* self )
 {
+       PyObject_GC_UnTrack( self );
        cppy::clear( &self->m_key_validator );
        cppy::clear( &self->m_value_validator );
+    delete atomdict_cast( self )->pointer;
+    atomdict_cast( self )->pointer = 0;
        PyDict_Type.tp_dealloc( pyobject_cast( self ) );
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/atom/src/atomlist.cpp 
new/atom-0.10.3/atom/src/atomlist.cpp
--- old/atom-0.10.0/atom/src/atomlist.cpp       2023-05-05 10:02:54.000000000 
+0200
+++ new/atom-0.10.3/atom/src/atomlist.cpp       2023-10-04 10:36:05.000000000 
+0200
@@ -310,9 +310,9 @@
 AtomList_dealloc( AtomList* self )
 {
     PyObject_GC_UnTrack( self );
+    cppy::clear( &self->validator );
     delete self->pointer;
     self->pointer = 0;
-    Py_CLEAR( self->validator );
     PyList_Type.tp_dealloc( pyobject_cast( self ) );
 }
 
@@ -466,62 +466,166 @@
 namespace PySStr
 {
 
-    class PyStringMaker
-    {
-
-    public:
-
-        PyStringMaker( const char* string ) : m_pystring( 0 )
-        {
-            m_pystring = PyUnicode_FromString( string );
-        }
-
-        PyObject* operator()()
-        {
-            return m_pystring.get();
-        }
-
-    private:
-
-        PyStringMaker();
-        cppy::ptr m_pystring;
-    };
+    static PyObject* typestr;
+    static PyObject* namestr;
+    static PyObject* objectstr;
+    static PyObject* valuestr ;
+    static PyObject* operationstr ;
+    static PyObject* itemstr ;
+    static PyObject* itemsstr ;
+    static PyObject* indexstr ;
+    static PyObject* keystr ;
+    static PyObject* reversestr ;
+    static PyObject* containerstr ;
+    static PyObject* __delitem__str ;
+    static PyObject* __iadd__str ;
+    static PyObject* __imul__str ;
+    static PyObject* __setitem__str ;
+    static PyObject* appendstr ;
+    static PyObject* extendstr ;
+    static PyObject* insertstr ;
+    static PyObject* popstr ;
+    static PyObject* removestr ;
+    static PyObject* sortstr ;
+    static PyObject* olditemstr ;
+    static PyObject* newitemstr ;
+    static PyObject* countstr ;
 
+}  // namespace PySStr
 
-    #define _STATIC_STRING( name )                \
-        static PyObject*                          \
-        name()                                    \
-        {                                         \
-            static PyStringMaker string( #name ); \
-            return string();                      \
-        }
 
-    _STATIC_STRING( type )
-    _STATIC_STRING( name )
-    _STATIC_STRING( object )
-    _STATIC_STRING( value )
-    _STATIC_STRING( operation )
-    _STATIC_STRING( item )
-    _STATIC_STRING( items )
-    _STATIC_STRING( index )
-    _STATIC_STRING( key )
-    _STATIC_STRING( reverse )
-    _STATIC_STRING( container )
-    _STATIC_STRING( __delitem__ )
-    _STATIC_STRING( __iadd__ )
-    _STATIC_STRING( __imul__ )
-    _STATIC_STRING( __setitem__ )
-    _STATIC_STRING( append )
-    _STATIC_STRING( extend )
-    _STATIC_STRING( insert )
-    _STATIC_STRING( pop )
-    _STATIC_STRING( remove )
-    _STATIC_STRING( sort )
-    _STATIC_STRING( olditem )
-    _STATIC_STRING( newitem )
-    _STATIC_STRING( count )
+bool
+init_containerlistchange()
+{
+    static bool alloced = false;
+    if( alloced )
+    {
+        return true;
+    }
 
-}  // namespace PySStr
+    PySStr::typestr = PyUnicode_InternFromString( "type" );
+    if( !PySStr::typestr )
+    {
+        return false;
+    }
+    PySStr::namestr = PyUnicode_InternFromString( "name" );
+    if( !PySStr::namestr )
+    {
+        return false;
+    }
+    PySStr::objectstr = PyUnicode_InternFromString( "object" );
+    if( !PySStr::objectstr )
+    {
+        return false;
+    }
+    PySStr::valuestr = PyUnicode_InternFromString( "value" );
+    if( !PySStr::valuestr )
+    {
+        return false;
+    }
+    PySStr::operationstr = PyUnicode_InternFromString( "operation" );
+    if( !PySStr::operationstr )
+    {
+        return false;
+    }
+    PySStr::itemstr = PyUnicode_InternFromString( "item" );
+    if( !PySStr::itemstr )
+    {
+        return false;
+    }
+    PySStr::itemsstr = PyUnicode_InternFromString( "items" );
+    if( !PySStr::itemsstr )
+    {
+        return false;
+    }
+    PySStr::indexstr = PyUnicode_InternFromString( "index" );
+    if( !PySStr::indexstr )
+    {
+        return false;
+    }
+    PySStr::keystr = PyUnicode_InternFromString( "key" );
+    if( !PySStr::keystr )
+    {
+        return false;
+    }
+    PySStr::reversestr = PyUnicode_InternFromString( "reverse" );
+    if( !PySStr::reversestr )
+    {
+        return false;
+    }
+    PySStr::containerstr = PyUnicode_InternFromString( "container" );
+    if( !PySStr::containerstr )
+    {
+        return false;
+    }
+    PySStr::__delitem__str = PyUnicode_InternFromString( "__delitem__" );
+    if( !PySStr::typestr )
+    {
+        return false;
+    }
+    PySStr::__iadd__str = PyUnicode_InternFromString( "__iadd__" );
+    if( !PySStr::__iadd__str )
+    {
+        return false;
+    }
+    PySStr::__imul__str = PyUnicode_InternFromString( "__imul__" );
+    if( !PySStr::__imul__str )
+    {
+        return false;
+    }
+    PySStr::__setitem__str = PyUnicode_InternFromString( "__setitem__" );
+    if( !PySStr::__setitem__str )
+    {
+        return false;
+    }
+    PySStr::appendstr = PyUnicode_InternFromString( "append" );
+    if( !PySStr::appendstr )
+    {
+        return false;
+    }
+    PySStr::extendstr = PyUnicode_InternFromString( "extend" );
+    if( !PySStr::extendstr )
+    {
+        return false;
+    }
+    PySStr::insertstr = PyUnicode_InternFromString( "insert" );
+    if( !PySStr::insertstr )
+    {
+        return false;
+    }
+    PySStr::popstr = PyUnicode_InternFromString( "pop" );
+    if( !PySStr::popstr )
+    {
+        return false;
+    }
+    PySStr::removestr = PyUnicode_InternFromString( "remove" );
+    if( !PySStr::removestr )
+    {
+        return false;
+    }
+    PySStr::sortstr = PyUnicode_InternFromString( "sort" );
+    if( !PySStr::sortstr )
+    {
+        return false;
+    }
+    PySStr::olditemstr = PyUnicode_InternFromString( "olditem" );
+    if( !PySStr::olditemstr )
+    {
+        return false;
+    }
+    PySStr::newitemstr = PyUnicode_InternFromString( "newitem" );
+    if( !PySStr::newitemstr )
+    {
+        return false;
+    }
+    PySStr::countstr = PyUnicode_InternFromString( "count" );
+    if( !PySStr::countstr )
+    {
+        return false;
+    }
+    alloced = true;
+    return true;
+}
 
 
 namespace
@@ -559,9 +663,9 @@
             cppy::ptr c( prepare_change() );
             if( !c )
                 return 0;  // LCOV_EXCL_LINE
-            if( PyDict_SetItem( c.get(), PySStr::operation(), PySStr::append() 
) != 0 )
+            if( PyDict_SetItem( c.get(), PySStr::operationstr, 
PySStr::appendstr ) != 0 )
                 return 0;
-            if( PyDict_SetItem( c.get(), PySStr::item(), m_validated.get() ) 
!= 0 )
+            if( PyDict_SetItem( c.get(), PySStr::itemstr, m_validated.get() ) 
!= 0 )
                 return 0;
             if( !post_change( c ) )
                 return 0;
@@ -580,15 +684,15 @@
             cppy::ptr c( prepare_change() );
             if( !c )
                 return 0;  // LCOV_EXCL_LINE
-            if( PyDict_SetItem( c.get(), PySStr::operation(), PySStr::insert() 
) != 0 )
+            if( PyDict_SetItem( c.get(), PySStr::operationstr, 
PySStr::insertstr ) != 0 )
                 return 0;
             // if the superclass call succeeds, then this is safe.
             Py_ssize_t where = PyLong_AsSsize_t( PyTuple_GET_ITEM( args, 0 ) );
             clip_index( where, size );
             cppy::ptr index( PyLong_FromSsize_t( where ) );
-            if( PyDict_SetItem( c.get(), PySStr::index(), index.get() ) != 0 )
+            if( PyDict_SetItem( c.get(), PySStr::indexstr, index.get() ) != 0 )
                 return 0;
-            if( PyDict_SetItem( c.get(), PySStr::item(), m_validated.get() ) 
!= 0)
+            if( PyDict_SetItem( c.get(), PySStr::itemstr, m_validated.get() ) 
!= 0)
                 return 0;
             if( !post_change( c ) )
                 return 0;
@@ -606,9 +710,9 @@
             cppy::ptr c( prepare_change() );
             if( !c )
                 return 0;  // LCOV_EXCL_LINE
-            if( PyDict_SetItem( c.get(), PySStr::operation(), PySStr::extend() 
) != 0 )
+            if( PyDict_SetItem( c.get(), PySStr::operationstr, 
PySStr::extendstr ) != 0 )
                 return 0;
-            if( PyDict_SetItem( c.get(), PySStr::items(), m_validated.get() ) 
!= 0 )
+            if( PyDict_SetItem( c.get(), PySStr::itemsstr, m_validated.get() ) 
!= 0 )
                 return 0;
             if( !post_change( c ) )
                 return 0;
@@ -633,7 +737,7 @@
             cppy::ptr c( prepare_change() );
             if( !c )
                 return 0;  // LCOV_EXCL_LINE
-            if( PyDict_SetItem( c.get(), PySStr::operation(), PySStr::pop() ) 
!= 0 )
+            if( PyDict_SetItem( c.get(), PySStr::operationstr, PySStr::popstr 
) != 0 )
                 return 0;
             // if the superclass call succeeds, then this is safe.
             Py_ssize_t i = -1;
@@ -642,9 +746,9 @@
             if( i < 0 )
                 i += size;
             cppy::ptr index( PyLong_FromSsize_t( i ) );
-            if( PyDict_SetItem( c.get(), PySStr::index(), index.get() ) != 0 )
+            if( PyDict_SetItem( c.get(), PySStr::indexstr, index.get() ) != 0 )
                 return 0;
-            if( PyDict_SetItem( c.get(), PySStr::item(), res.get() ) != 0 )
+            if( PyDict_SetItem( c.get(), PySStr::itemstr, res.get() ) != 0 )
                 return 0;
             if( !post_change( c ) )
                 return 0;
@@ -662,9 +766,9 @@
             cppy::ptr c( prepare_change() );
             if( !c )
                 return 0;  // LCOV_EXCL_LINE
-            if( PyDict_SetItem( c.get(), PySStr::operation(), PySStr::remove() 
) != 0)
+            if( PyDict_SetItem( c.get(), PySStr::operationstr, 
PySStr::removestr ) != 0)
                 return 0;
-            if( PyDict_SetItem( c.get(), PySStr::item(), value ) != 0 )
+            if( PyDict_SetItem( c.get(), PySStr::itemstr, value ) != 0 )
                 return 0;
             if( !post_change( c ) )
                 return 0;
@@ -682,7 +786,7 @@
             cppy::ptr c( prepare_change() );
             if( !c )
                 return 0;  // LCOV_EXCL_LINE
-            if( PyDict_SetItem( c.get(), PySStr::operation(), 
PySStr::reverse() ) != 0)
+            if( PyDict_SetItem( c.get(), PySStr::operationstr, 
PySStr::reversestr ) != 0)
                 return 0;
             if( !post_change( c ) )
                 return 0;
@@ -713,16 +817,16 @@
             cppy::ptr c( prepare_change() );
             if( !c )
                 return 0;  // LCOV_EXCL_LINE
-            if( PyDict_SetItem( c.get(), PySStr::operation(), PySStr::sort() ) 
!= 0 )
+            if( PyDict_SetItem( c.get(), PySStr::operationstr, PySStr::sortstr 
) != 0 )
                 return 0;
             PyObject* key = Py_None;
             int rev = 0;
             if( !PyArg_ParseTupleAndKeywords(
                 args, kwargs, "|Oi", kwlist, &key, &rev ) )
                 return 0;
-            if( PyDict_SetItem( c.get(), PySStr::key(), key ) != 0)
+            if( PyDict_SetItem( c.get(), PySStr::keystr, key ) != 0)
                 return 0;
-            if( PyDict_SetItem( c.get(), PySStr::reverse(), rev ? Py_True : 
Py_False ) != 0 )
+            if( PyDict_SetItem( c.get(), PySStr::reversestr, rev ? Py_True : 
Py_False ) != 0 )
                 return 0;
             if( !post_change( c ) )
                 return 0;
@@ -740,9 +844,9 @@
             cppy::ptr c( prepare_change() );
             if( !c )
                 return 0;  // LCOV_EXCL_LINE
-            if( PyDict_SetItem( c.get(), PySStr::operation(), 
PySStr::__iadd__() ) != 0 )
+            if( PyDict_SetItem( c.get(), PySStr::operationstr, 
PySStr::__iadd__str ) != 0 )
                 return 0;
-            if( PyDict_SetItem( c.get(), PySStr::items(), m_validated.get() ) 
!= 0 )
+            if( PyDict_SetItem( c.get(), PySStr::itemsstr, m_validated.get() ) 
!= 0 )
                 return 0;
             if( !post_change( c ) )
                 return 0;
@@ -761,12 +865,12 @@
             cppy::ptr c( prepare_change() );
             if( !c )
                 return 0;  // LCOV_EXCL_LINE
-            if( PyDict_SetItem( c.get(), PySStr::operation(), 
PySStr::__imul__() ) != 0 )
+            if( PyDict_SetItem( c.get(), PySStr::operationstr, 
PySStr::__imul__str ) != 0 )
                 return 0;
             cppy::ptr pycount( PyLong_FromSsize_t( count ) );
             if( !pycount )
                 return 0;
-            if( PyDict_SetItem( c.get(), PySStr::count(), pycount.get() ) != 0 
)
+            if( PyDict_SetItem( c.get(), PySStr::countstr, pycount.get() ) != 
0 )
                 return 0;
             if( !post_change( c ) )
                 return 0;
@@ -848,13 +952,13 @@
         cppy::ptr c( PyDict_New() );
         if( !c )
             return 0;
-        if( PyDict_SetItem( c.get(), PySStr::type(), PySStr::container() ) != 
0 )
+        if( PyDict_SetItem( c.get(), PySStr::typestr, PySStr::containerstr ) 
!= 0 )
             return 0;
-        if( PyDict_SetItem( c.get(), PySStr::name(), member()->name ) != 0 )
+        if( PyDict_SetItem( c.get(), PySStr::namestr, member()->name ) != 0 )
             return 0;
-        if( PyDict_SetItem( c.get(), PySStr::object(), pyobject_cast( atom() ) 
) != 0 )
+        if( PyDict_SetItem( c.get(), PySStr::objectstr, pyobject_cast( atom() 
) ) != 0 )
             return 0;
-        if( PyDict_SetItem( c.get(), PySStr::value(), m_list.get() ) != 0 )
+        if( PyDict_SetItem( c.get(), PySStr::valuestr, m_list.get() ) != 0 )
             return 0;
         return c.release();
     }
@@ -885,21 +989,21 @@
             return -1;
         if( n )
         {
-            if( PyDict_SetItem( c.get(), PySStr::operation(), 
PySStr::__setitem__() ) != 0 )
+            if( PyDict_SetItem( c.get(), PySStr::operationstr, 
PySStr::__setitem__str ) != 0 )
                 return -1;
-            if( PyDict_SetItem( c.get(), PySStr::olditem(), o.get() ) != 0)
+            if( PyDict_SetItem( c.get(), PySStr::olditemstr, o.get() ) != 0)
                 return -1;
-            if( PyDict_SetItem( c.get(), PySStr::newitem(), n.get() ) != 0)
+            if( PyDict_SetItem( c.get(), PySStr::newitemstr, n.get() ) != 0)
                 return -1;
         }
         else
         {
-            if( PyDict_SetItem( c.get(), PySStr::operation(), 
PySStr::__delitem__() ) != 0 )
+            if( PyDict_SetItem( c.get(), PySStr::operationstr, 
PySStr::__delitem__str ) != 0 )
                 return -1;
-            if( PyDict_SetItem( c.get(), PySStr::item(), o.get() ) != 0 )
+            if( PyDict_SetItem( c.get(), PySStr::itemstr, o.get() ) != 0 )
                 return -1;
         }
-        if( PyDict_SetItem( c.get(), PySStr::index(), i.get() ) != 0 )
+        if( PyDict_SetItem( c.get(), PySStr::indexstr, i.get() ) != 0 )
             return -1;
         if( !post_change( c ) )
             return -1;
@@ -936,10 +1040,10 @@
 AtomCList_dealloc( AtomCList* self )
 {
     PyObject_GC_UnTrack( self );
-    Py_CLEAR( self->member );
+    cppy::clear( &self->member );
+    cppy::clear( &atomlist_cast( self )->validator );
     delete atomlist_cast( self )->pointer;
     atomlist_cast( self )->pointer = 0;
-    Py_CLEAR( atomlist_cast( self )->validator );
     PyList_Type.tp_dealloc( pyobject_cast( self ) );
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/atom/src/atomlist.h 
new/atom-0.10.3/atom/src/atomlist.h
--- old/atom-0.10.0/atom/src/atomlist.h 2023-05-05 10:02:54.000000000 +0200
+++ new/atom-0.10.3/atom/src/atomlist.h 2023-10-04 10:36:05.000000000 +0200
@@ -41,6 +41,9 @@
 
 };
 
+bool
+init_containerlistchange();
+
 
 // POD struct - all member fields are considered private
 struct AtomCList
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/atom/src/atomset.cpp 
new/atom-0.10.3/atom/src/atomset.cpp
--- old/atom-0.10.0/atom/src/atomset.cpp        2023-05-05 10:02:54.000000000 
+0200
+++ new/atom-0.10.3/atom/src/atomset.cpp        2023-10-04 10:36:05.000000000 
+0200
@@ -95,7 +95,10 @@
 
 void AtomSet_dealloc( AtomSet* self )
 {
+       PyObject_GC_UnTrack( self );
        cppy::clear( &self->m_value_validator );
+       delete atomset_cast( self )->pointer;
+    atomset_cast( self )->pointer = 0;
        PySet_Type.tp_dealloc( pyobject_cast( self ) );
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/atom/src/catommodule.cpp 
new/atom-0.10.3/atom/src/catommodule.cpp
--- old/atom-0.10.0/atom/src/catommodule.cpp    2023-05-05 10:02:54.000000000 
+0200
+++ new/atom-0.10.3/atom/src/catommodule.cpp    2023-10-04 10:36:05.000000000 
+0200
@@ -178,6 +178,10 @@
     {
         return -1;
     }
+    if( !atom::init_containerlistchange() )
+    {
+        return -1;
+    }
     if( !add_objects( mod ) )
     {
         return -1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/atom/version.py 
new/atom-0.10.3/atom/version.py
--- old/atom-0.10.0/atom/version.py     2023-05-05 10:03:21.000000000 +0200
+++ new/atom-0.10.3/atom/version.py     2023-10-04 10:36:33.000000000 +0200
@@ -12,7 +12,7 @@
 #: A namedtuple of the version info for the current release.
 _version_info = namedtuple("_version_info", "major minor micro status")
 
-parts = "0.10.0".split(".", 3)
+parts = "0.10.3".split(".", 3)
 version_info = _version_info(
     int(parts[0]),
     int(parts[1]),
@@ -23,4 +23,4 @@
 # Remove everything but the 'version_info' from this module.
 del namedtuple, _version_info, parts
 
-__version__ = "0.10.0"
+__version__ = "0.10.3"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/atom.egg-info/PKG-INFO 
new/atom-0.10.3/atom.egg-info/PKG-INFO
--- old/atom-0.10.0/atom.egg-info/PKG-INFO      2023-05-05 10:03:22.000000000 
+0200
+++ new/atom-0.10.3/atom.egg-info/PKG-INFO      2023-10-04 10:36:34.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: atom
-Version: 0.10.0
+Version: 0.10.3
 Summary: Memory efficient Python objects
 Author-email: The Nucleic Development Team <[email protected]>
 Maintainer-email: "Matthieu C. Dartiailh" <[email protected]>
@@ -98,6 +98,7 @@
 Requires-Python: >=3.8
 Description-Content-Type: text/x-rst
 License-File: LICENSE
+Requires-Dist: typing_extensions; python_version < "3.11"
 
 Welcome to Atom
 ===============
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/atom.egg-info/SOURCES.txt 
new/atom-0.10.3/atom.egg-info/SOURCES.txt
--- old/atom-0.10.0/atom.egg-info/SOURCES.txt   2023-05-05 10:03:22.000000000 
+0200
+++ new/atom-0.10.3/atom.egg-info/SOURCES.txt   2023-10-04 10:36:34.000000000 
+0200
@@ -205,6 +205,7 @@
 tests/test_get_behaviors.py
 tests/test_get_set_state.py
 tests/test_getstate_behaviors.py
+tests/test_mem.py
 tests/test_member.py
 tests/test_observe.py
 tests/test_post_behaviors.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/releasenotes.rst 
new/atom-0.10.3/releasenotes.rst
--- old/atom-0.10.0/releasenotes.rst    2023-05-05 10:02:54.000000000 +0200
+++ new/atom-0.10.3/releasenotes.rst    2023-10-04 10:36:05.000000000 +0200
@@ -1,6 +1,25 @@
 Atom Release Notes
 ==================
 
+0.10.3 - 04/10/2023
+-------------------
+
+- fix a an issue when using add_member to override an existing member PR #204
+
+  Once again a huge thanks to @frmdstryr for the report and fix
+
+0.10.2 - 02/10/2023
+-------------------
+
+- fix a memory leak caused by Dict, Defaultdict and Set members #202
+
+  A huge thanks to @frmdstryr for the report and fix
+
+0.10.1 - 11/09/2023
+-------------------
+
+- add support for Python 3.12 PR #200
+
 0.10.0 - 05/05/2023
 -------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/test_requirements.txt 
new/atom-0.10.3/test_requirements.txt
--- old/atom-0.10.0/test_requirements.txt       2023-05-05 10:02:54.000000000 
+0200
+++ new/atom-0.10.3/test_requirements.txt       2023-10-04 10:36:05.000000000 
+0200
@@ -2,3 +2,4 @@
 pytest-cov
 pytest-mypy-plugins
 pytest-benchmark
+psutil
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/tests/test_atom.py 
new/atom-0.10.3/tests/test_atom.py
--- old/atom-0.10.0/tests/test_atom.py  2023-05-05 10:02:54.000000000 +0200
+++ new/atom-0.10.3/tests/test_atom.py  2023-10-04 10:36:05.000000000 +0200
@@ -164,6 +164,29 @@
     assert "a" in B().members()
 
 
+def test_add_member_overridden_member():
+    class A(Atom):
+        a = Int()
+        b = Int()
+
+        def _observe_b(self, change):
+            pass
+
+    class B(A):
+        c = Int()
+
+    new = Str()
+    add_member(B, "b", new)
+
+    r = B(a=1, b="abc")
+    assert r.a == 1
+    assert r.b == "abc"
+    assert B.a.index == 0
+    assert B.b.index == 1
+    assert B.c.index == 2
+    assert B.b.has_observer("_observe_b")
+
+
 def test_cloning_members():
     """Test cloning a member when appropriate.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/tests/test_atomlist.py 
new/atom-0.10.3/tests/test_atomlist.py
--- old/atom-0.10.0/tests/test_atomlist.py      2023-05-05 10:02:54.000000000 
+0200
+++ new/atom-0.10.3/tests/test_atomlist.py      2023-10-04 10:36:05.000000000 
+0200
@@ -396,8 +396,8 @@
         self.model = None
 
     def test_list_types(self):
-        assert type(self.model.untyped) == atomlist
-        assert type(self.model.typed) == atomlist
+        assert type(self.model.untyped) is atomlist
+        assert type(self.model.typed) is atomlist
 
     def test_pickle(self):
         data = list(range(10))
@@ -454,8 +454,8 @@
         self.model = None
 
     def test_list_types(self):
-        assert type(self.model.untyped) == atomclist
-        assert type(self.model.typed) == atomclist
+        assert type(self.model.untyped) is atomclist
+        assert type(self.model.typed) is atomclist
 
 
 @pytest.fixture
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/atom-0.10.0/tests/test_mem.py 
new/atom-0.10.3/tests/test_mem.py
--- old/atom-0.10.0/tests/test_mem.py   1970-01-01 01:00:00.000000000 +0100
+++ new/atom-0.10.3/tests/test_mem.py   2023-10-04 10:36:05.000000000 +0200
@@ -0,0 +1,101 @@
+# 
--------------------------------------------------------------------------------------
+# Copyright (c) 2023, Nucleic Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file LICENSE, distributed with this software.
+# 
--------------------------------------------------------------------------------------
+import gc
+import time
+from multiprocessing import Process
+
+import pytest
+
+from atom.api import Atom, DefaultDict, Dict, Int, List, Set, atomref
+
+try:
+    import psutil
+
+    PSUTIL_UNAVAILABLE = False
+except ImportError:
+    PSUTIL_UNAVAILABLE = True
+
+TIMEOUT = 6
+
+
+class DictObj(Atom):
+    data = Dict(default={"a": 0})
+
+
+class DefaultDictObj(Atom):
+    data = DefaultDict(value=Int(), default={1: 1})
+
+
+class ListObj(Atom):
+    data = List(default=[1, 2, 3])
+
+
+class SetObj(Atom):
+    data = Set(default={1, 2, 3})
+
+
+class RefObj(Atom):
+    data = Int()
+
+
+MEM_TESTS = {
+    "dict": DictObj,
+    "defaultdict": DefaultDictObj,
+    "list": ListObj,
+    "set": SetObj,
+    "atomref": RefObj,
+}
+
+
+def memtest(cls):
+    # Create object in a loop
+    # Memory usage should settle out and not change
+    while True:
+        obj = cls()
+        obj.data  # Force creation
+        del obj
+        gc.collect()
+
+
+def atomreftest(cls):
+    obj = cls()
+    obj.data
+    while True:
+        ref = atomref(obj)  # noqa
+        del ref
+        gc.collect()
+
+
[email protected](PSUTIL_UNAVAILABLE, reason="psutil is not installed")
[email protected]("label", MEM_TESTS.keys())
+def test_mem_usage(label):
+    TestClass = MEM_TESTS[label]
+    if "atomref" in label:
+        target = atomreftest
+    else:
+        target = memtest
+
+    p = Process(target=target, args=(TestClass,))
+    p.start()
+    try:
+        stats = psutil.Process(p.pid)
+        time.sleep(TIMEOUT * 1 / 4)
+        first_info = stats.memory_info()
+        time.sleep(TIMEOUT * 3 / 4)
+        last_info = stats.memory_info()
+        # Allow slight memory decrease over time to make tests more resilient
+        if first_info != last_info:
+            assert (
+                first_info.rss >= last_info.rss >= 0
+            ), "Memory leaked:\n  {}\n  {}".format(first_info, last_info)
+            assert (
+                first_info.vms >= last_info.vms >= 0
+            ), "Memory leaked:\n  {}\n  {}".format(first_info, last_info)
+    finally:
+        p.kill()
+        p.join()

Reply via email to