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 2024-09-01 19:21:29 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-atom (Old) and /work/SRC/openSUSE:Factory/.python-atom.new.2698 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-atom" Sun Sep 1 19:21:29 2024 rev:14 rq:1197801 version:0.10.5 Changes: -------- --- /work/SRC/openSUSE:Factory/python-atom/python-atom.changes 2024-01-30 18:26:48.864971056 +0100 +++ /work/SRC/openSUSE:Factory/.python-atom.new.2698/python-atom.changes 2024-09-01 19:21:44.420785462 +0200 @@ -1,0 +2,9 @@ +Thu Aug 22 10:26:48 UTC 2024 - Frantisek Simorda <frantisek.simo...@suse.com> + +- Update to 0.10.5: + * fix ruff config + * Merge pull request #209 from nucleic/ruff-fixes + * ci: do not build oldest python on macos + * Fix memory leak in pickle creation (#213) + +------------------------------------------------------------------- Old: ---- atom-0.10.4.tar.gz New: ---- atom-0.10.5.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-atom.spec ++++++ --- /var/tmp/diff_new_pack.3thxjv/_old 2024-09-01 19:21:45.228818544 +0200 +++ /var/tmp/diff_new_pack.3thxjv/_new 2024-09-01 19:21:45.228818544 +0200 @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-atom -Version: 0.10.4 +Version: 0.10.5 Release: 0 Summary: Memory efficient Python objects License: BSD-3-Clause ++++++ atom-0.10.4.tar.gz -> atom-0.10.5.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atom-0.10.4/.github/workflows/ci.yml new/atom-0.10.5/.github/workflows/ci.yml --- old/atom-0.10.4/.github/workflows/ci.yml 2024-01-23 16:29:13.000000000 +0100 +++ new/atom-0.10.5/.github/workflows/ci.yml 2024-07-04 08:29:58.000000000 +0200 @@ -47,7 +47,7 @@ - name: Linting if: always() run: | - ruff atom examples tests + ruff check atom examples tests - name: Typing if: always() run: | @@ -95,6 +95,11 @@ matrix: os: [ubuntu-latest, windows-latest, macos-latest] python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + exclude: + - python-version: '3.8' + os: macos-latest + - python-version: '3.9' + os: macos-latest steps: - uses: actions/checkout@v4 - name: Get history and tags for SCM versioning to work diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atom-0.10.4/PKG-INFO new/atom-0.10.5/PKG-INFO --- old/atom-0.10.4/PKG-INFO 2024-01-23 16:29:27.701215700 +0100 +++ new/atom-0.10.5/PKG-INFO 2024-07-04 08:30:05.404321700 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: atom -Version: 0.10.4 +Version: 0.10.5 Summary: Memory efficient Python objects Author-email: The Nucleic Development Team <sccolb...@gmail.com> Maintainer-email: "Matthieu C. Dartiailh" <m.dartia...@gmail.com> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atom-0.10.4/atom/src/catom.cpp new/atom-0.10.5/atom/src/catom.cpp --- old/atom-0.10.4/atom/src/catom.cpp 2024-01-23 16:29:13.000000000 +0100 +++ new/atom-0.10.5/atom/src/catom.cpp 2024-07-04 08:29:58.000000000 +0200 @@ -375,8 +375,9 @@ CAtom_getstate( CAtom* self ) { cppy::ptr stateptr = PyDict_New(); - if ( !stateptr ) + if ( !stateptr ) { return PyErr_NoMemory(); // LCOV_EXCL_LINE + } cppy::ptr selfptr(pyobject_cast(self), true); @@ -391,26 +392,33 @@ // Copy __slots__ if present. This assumes copyreg._slotnames was called // during AtomMeta's initialization { - cppy::ptr typeptr = PyObject_Type(selfptr.get()); - if (!typeptr) - return 0; - cppy::ptr slotnamesptr = typeptr.getattr("__slotnames__"); - if (!slotnamesptr.get()) + PyObject* typedict = Py_TYPE(selfptr.get())->tp_dict; + cppy::ptr slotnamesptr(PyDict_GetItemString(typedict, "__slotnames__"), true); + if ( !slotnamesptr ) { return 0; - if (!PyList_CheckExact(slotnamesptr.get())) + } + if ( !PyList_CheckExact(slotnamesptr.get()) ) { return cppy::system_error( "slot names" ); + } for ( Py_ssize_t i=0; i < PyList_GET_SIZE(slotnamesptr.get()); i++ ) { PyObject *name = PyList_GET_ITEM(slotnamesptr.get(), i); cppy::ptr value = selfptr.getattr(name); - if (!value || PyDict_SetItem(stateptr.get(), name, value.get()) ) + if (!value ) { + // Following CPython impl it is not an error if the attribute is + // not present. + continue; + } + else if ( PyDict_SetItem(stateptr.get(), name, value.get()) ) { return 0; + } } } cppy::ptr membersptr = selfptr.getattr(atom_members); - if ( !membersptr || !PyDict_CheckExact( membersptr.get() ) ) + if ( !membersptr || !PyDict_CheckExact( membersptr.get() ) ) { return cppy::system_error( "atom members" ); + } PyObject *name, *member; Py_ssize_t pos = 0; @@ -421,9 +429,8 @@ } int test = PyObject_IsTrue( should_gs.get() ); if ( test == 1) { - PyObject *value = member_cast( member )->getattr( self ); - if (!value || PyDict_SetItem( stateptr.get(), name, value ) ) { - Py_XDECREF( value ); + cppy::ptr value = member_cast( member )->getattr( self ); + if (!value || PyDict_SetItem( stateptr.get(), name, value.get() ) ) { return 0; } } @@ -433,8 +440,9 @@ } // Frozen state - if ( self->is_frozen() && PyDict_SetItem(stateptr.get(), atom_flags, Py_None) ) + if ( self->is_frozen() && PyDict_SetItem(stateptr.get(), atom_flags, Py_None) ) { return 0; + } return stateptr.release(); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atom-0.10.4/atom/version.py new/atom-0.10.5/atom/version.py --- old/atom-0.10.4/atom/version.py 2024-01-23 16:29:27.000000000 +0100 +++ new/atom-0.10.5/atom/version.py 2024-07-04 08:30:05.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.4".split(".", 3) +parts = "0.10.5".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.4" +__version__ = "0.10.5" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atom-0.10.4/atom.egg-info/PKG-INFO new/atom-0.10.5/atom.egg-info/PKG-INFO --- old/atom-0.10.4/atom.egg-info/PKG-INFO 2024-01-23 16:29:27.000000000 +0100 +++ new/atom-0.10.5/atom.egg-info/PKG-INFO 2024-07-04 08:30:05.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: atom -Version: 0.10.4 +Version: 0.10.5 Summary: Memory efficient Python objects Author-email: The Nucleic Development Team <sccolb...@gmail.com> Maintainer-email: "Matthieu C. Dartiailh" <m.dartia...@gmail.com> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atom-0.10.4/docs/source/examples/example_doc_generator.py new/atom-0.10.5/docs/source/examples/example_doc_generator.py --- old/atom-0.10.4/docs/source/examples/example_doc_generator.py 2024-01-23 16:29:13.000000000 +0100 +++ new/atom-0.10.5/docs/source/examples/example_doc_generator.py 2024-07-04 08:29:58.000000000 +0200 @@ -87,7 +87,7 @@ # Add the script to the Python Path old_python_path = sys.path - sys.path = sys.path + [os.path.dirname(script_path)] + sys.path = [*sys.path, os.path.dirname(script_path)] # Restore Python path. sys.path = old_python_path diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atom-0.10.4/pyproject.toml new/atom-0.10.5/pyproject.toml --- old/atom-0.10.4/pyproject.toml 2024-01-23 16:29:13.000000000 +0100 +++ new/atom-0.10.5/pyproject.toml 2024-07-04 08:29:58.000000000 +0200 @@ -74,16 +74,18 @@ [tool.ruff] src = ["src"] - select = ["C", "E", "F", "W", "I", "C90", "RUF"] - extend-ignore = ["E501", "RUF012"] line-length = 88 - [tool.ruff.isort] - combine-as-imports = true - known-first-party = ["atom"] + [tool.ruff.lint] + select = ["C", "E", "F", "W", "I", "C90", "RUF"] + extend-ignore = ["E501", "RUF012"] - [tool.ruff.mccabe] - max-complexity = 20 + [tool.ruff.lint.isort] + combine-as-imports = true + known-first-party = ["atom"] + + [tool.ruff.lint.mccabe] + max-complexity = 20 [tool.mypy] follow_imports = "normal" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atom-0.10.4/tests/test_atom_from_annotations.py new/atom-0.10.5/tests/test_atom_from_annotations.py --- old/atom-0.10.4/tests/test_atom_from_annotations.py 2024-01-23 16:29:13.000000000 +0100 +++ new/atom-0.10.5/tests/test_atom_from_annotations.py 2024-07-04 08:29:58.000000000 +0200 @@ -168,7 +168,7 @@ assert A.a.validate_mode[1] == (annotation.__origin__,) elif member is Subclass: if isinstance(annotation.__args__[0], TypeVar): - assert A.a.validate_mode[1] == object + assert A.a.validate_mode[1] is object else: assert A.a.validate_mode[1] == annotation.__args__[0] else: @@ -254,9 +254,9 @@ assert type(v) is type(mv) assert f(A()) == mf(A()) else: - assert type(A.a.item) is type(member.item) # noqa: E721 + assert type(A.a.item) is type(member.item) if isinstance(member.item, List): - assert type(A.a.item.item) is type(member.item.item) # noqa: E721 + assert type(A.a.item.item) is type(member.item.item) @pytest.mark.parametrize( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atom-0.10.4/tests/test_mem.py new/atom-0.10.5/tests/test_mem.py --- old/atom-0.10.4/tests/test_mem.py 2024-01-23 16:29:13.000000000 +0100 +++ new/atom-0.10.5/tests/test_mem.py 2024-07-04 08:29:58.000000000 +0200 @@ -1,5 +1,5 @@ # -------------------------------------------------------------------------------------- -# Copyright (c) 2023, Nucleic Development Team. +# Copyright (c) 2023-2024, Nucleic Development Team. # # Distributed under the terms of the Modified BSD License. # @@ -7,8 +7,10 @@ # -------------------------------------------------------------------------------------- import gc import os +import pickle import sys import time +import tracemalloc from multiprocessing import Process import pytest @@ -53,6 +55,13 @@ "atomref": RefObj, } +PICKLE_MEM_TESTS = { + "dict": DictObj, + "defaultdict": DefaultDictObj, + "list": ListObj, + "set": SetObj, +} + def memtest(cls): # Create object in a loop @@ -105,3 +114,34 @@ finally: p.kill() p.join() + + +@pytest.mark.parametrize("label", PICKLE_MEM_TESTS.keys()) +def test_pickle_mem_usage(label): + TestClass = PICKLE_MEM_TESTS[label] + + obj = TestClass() + + for _ in range(100): + pickle.loads(pickle.dumps(obj)) + + gc.collect() + tracemalloc.start() + for i in range(10000): + pck = pickle.dumps(obj) + pickle.loads(pck) + del pck + gc.collect() + for stat in ( + tracemalloc.take_snapshot() + .filter_traces( + [ + tracemalloc.Filter(True, "*/atom/*"), + tracemalloc.Filter(False, "*/tests/*"), + ] + ) + .statistics("lineno") + ): + # not sure why I sometimes see a 2 here but the original buggy version + # reported values > 50 + assert stat.count < 5 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atom-0.10.4/tests/type_checking/test_subclass.yml new/atom-0.10.5/tests/type_checking/test_subclass.yml --- old/atom-0.10.4/tests/type_checking/test_subclass.yml 2024-01-23 16:29:13.000000000 +0100 +++ new/atom-0.10.5/tests/type_checking/test_subclass.yml 2024-07-04 08:29:58.000000000 +0200 @@ -1,60 +1,61 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2021, Nucleic Development Team. +# Copyright (c) 2021-2024, Nucleic Development Team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. #------------------------------------------------------------------------------ - case: subclass + skip: sys.version_info < (3, 9) # 3.8 uses Type[] while 3.9+ uses type[] parametrized: - member: Subclass member_instance: Subclass(A) - member_type: atom.subclass.Subclass[Type[main.A]] - member_value_type: Type[main.A] + member_type: atom.subclass.Subclass[type[main.A]] + member_value_type: type[main.A] - member: Subclass member_instance: Subclass(A, B) - member_type: atom.subclass.Subclass[Type[main.A]] - member_value_type: Type[main.A] + member_type: atom.subclass.Subclass[type[main.A]] + member_value_type: type[main.A] - member: Subclass member_instance: Subclass((A,)) - member_type: atom.subclass.Subclass[Type[main.A]] - member_value_type: Type[main.A] + member_type: atom.subclass.Subclass[type[main.A]] + member_value_type: type[main.A] - member: Subclass member_instance: Subclass((A,), B) - member_type: atom.subclass.Subclass[Type[main.A]] - member_value_type: Type[main.A] + member_type: atom.subclass.Subclass[type[main.A]] + member_value_type: type[main.A] - member: Subclass member_instance: Subclass((int, A)) - member_type: atom.subclass.Subclass[Union[Type[builtins.int], Type[main.A]]] - member_value_type: Union[Type[builtins.int], Type[main.A]] + member_type: atom.subclass.Subclass[Union[type[builtins.int], type[main.A]]] + member_value_type: Union[type[builtins.int], type[main.A]] - member: Subclass member_instance: Subclass((int, A), B) - member_type: atom.subclass.Subclass[Union[Type[builtins.int], Type[main.A]]] - member_value_type: Union[Type[builtins.int], Type[main.A]] + member_type: atom.subclass.Subclass[Union[type[builtins.int], type[main.A]]] + member_value_type: Union[type[builtins.int], type[main.A]] - member: Subclass member_instance: Subclass((int, A, str)) - member_type: atom.subclass.Subclass[Union[Type[builtins.int], Type[main.A], Type[builtins.str]]] - member_value_type: Union[Type[builtins.int], Type[main.A], Type[builtins.str]] + member_type: atom.subclass.Subclass[Union[type[builtins.int], type[main.A], type[builtins.str]]] + member_value_type: Union[type[builtins.int], type[main.A], type[builtins.str]] - member: Subclass member_instance: Subclass((int, A, str), B) - member_type: atom.subclass.Subclass[Union[Type[builtins.int], Type[main.A], Type[builtins.str]]] - member_value_type: Union[Type[builtins.int], Type[main.A], Type[builtins.str]] + member_type: atom.subclass.Subclass[Union[type[builtins.int], type[main.A], type[builtins.str]]] + member_value_type: Union[type[builtins.int], type[main.A], type[builtins.str]] - member: ForwardSubclass member_instance: ForwardSubclass(resolve1) - member_type: atom.subclass.ForwardSubclass[Type[main.A]] - member_value_type: Type[main.A] + member_type: atom.subclass.ForwardSubclass[type[main.A]] + member_value_type: type[main.A] - member: ForwardSubclass member_instance: ForwardSubclass(resolve2) - member_type: atom.subclass.ForwardSubclass[Type[main.A]] - member_value_type: Type[main.A] + member_type: atom.subclass.ForwardSubclass[type[main.A]] + member_value_type: type[main.A] - member: ForwardSubclass member_instance: ForwardSubclass(resolve3) - member_type: atom.subclass.ForwardSubclass[Union[Type[builtins.int], Type[main.A]]] - member_value_type: Union[Type[builtins.int], Type[main.A]] + member_type: atom.subclass.ForwardSubclass[Union[type[builtins.int], type[main.A]]] + member_value_type: Union[type[builtins.int], type[main.A]] - member: ForwardSubclass member_instance: ForwardSubclass(resolve4) - member_type: atom.subclass.ForwardSubclass[Union[Type[builtins.int], Type[main.A], Type[builtins.str]]] - member_value_type: Union[Type[builtins.int], Type[main.A], Type[builtins.str]] + member_type: atom.subclass.ForwardSubclass[Union[type[builtins.int], type[main.A], type[builtins.str]]] + member_value_type: Union[type[builtins.int], type[main.A], type[builtins.str]] main: | import io from typing import Tuple, Type