Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-dill for openSUSE:Factory 
checked in at 2024-10-23 21:09:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-dill (Old)
 and      /work/SRC/openSUSE:Factory/.python-dill.new.26871 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-dill"

Wed Oct 23 21:09:46 2024 rev:15 rq:1217040 version:0.3.9

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-dill/python-dill.changes  2024-09-01 
19:21:49.356987558 +0200
+++ /work/SRC/openSUSE:Factory/.python-dill.new.26871/python-dill.changes       
2024-10-23 21:10:53.960245404 +0200
@@ -1,0 +2,19 @@
+Tue Oct 22 13:27:09 UTC 2024 - Dirk Müller <[email protected]>
+
+- update to 0.3.9:
+  * further skip BufferedRandomType if does not exist
+  * remove stray import of dbm in objects
+  * Add `UnpicklingError` import for `dill.load_session()` to fix
+    #648
+  * fix fencepost error when getting source inside decorator in
+    interpreter (fixes #603)
+  * type check for Integral, bool by value
+  * diff USE_NUMPY imports numpy.ma
+  * adjust testing to account for frame.f_locals as a proxy in
+    3.13
+  * better handle import strings of numpy scalars
+  * handle a ThreadHandleType
+  * more extensive testing for dill.source
+  * add formal support for python 3.13
+
+-------------------------------------------------------------------

Old:
----
  dill-0.3.8.tar.gz

New:
----
  dill-0.3.9.tar.gz

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

Other differences:
------------------
++++++ python-dill.spec ++++++
--- /var/tmp/diff_new_pack.vvVCxs/_old  2024-10-23 21:10:54.552270116 +0200
+++ /var/tmp/diff_new_pack.vvVCxs/_new  2024-10-23 21:10:54.552270116 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-dill
-Version:        0.3.8
+Version:        0.3.9
 Release:        0
 Summary:        Module to serialize all of Python
 License:        BSD-3-Clause

++++++ dill-0.3.8.tar.gz -> dill-0.3.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/.travis.yml new/dill-0.3.9/.travis.yml
--- old/dill-0.3.8/.travis.yml  2024-01-28 00:44:53.000000000 +0100
+++ new/dill-0.3.9/.travis.yml  2024-09-29 02:04:07.000000000 +0200
@@ -26,15 +26,14 @@
         - python: 'pypy3.8-7.3.9' # at 7.3.11
           env:
 
-        - python: 'pypy3.9-7.3.9' # at 7.3.15
+        - python: 'pypy3.9-7.3.9' # at 7.3.16
           env:
 
-        - python: 'pypy3.10-7.3.15'
+        - python: 'pypy3.10-7.3.17'
           env:
 
     allow_failures:
-        - python: '3.13-dev'
-        - python: 'pypy3.10-7.3.15' # CI missing
+        - python: 'pypy3.10-7.3.17' # CI missing
     fast_finish: true
 
 cache:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/dill/__diff.py 
new/dill-0.3.9/dill/__diff.py
--- old/dill-0.3.8/dill/__diff.py       2024-01-28 00:44:53.000000000 +0100
+++ new/dill-0.3.9/dill/__diff.py       2024-09-29 02:04:07.000000000 +0200
@@ -15,7 +15,7 @@
 import sys
 import types
 try:
-    import numpy
+    import numpy.ma
     HAS_NUMPY = True
 except ImportError:
     HAS_NUMPY = False
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/dill/_dill.py new/dill-0.3.9/dill/_dill.py
--- old/dill-0.3.8/dill/_dill.py        2024-01-28 00:44:53.000000000 +0100
+++ new/dill-0.3.9/dill/_dill.py        2024-09-29 02:04:07.000000000 +0200
@@ -56,6 +56,14 @@
 from pickle import GLOBAL, POP
 from _thread import LockType
 from _thread import RLock as RLockType
+try:
+    from _thread import _ExceptHookArgs as ExceptHookArgsType
+except ImportError:
+    ExceptHookArgsType = None
+try:
+    from _thread import _ThreadHandle as ThreadHandleType
+except ImportError:
+    ThreadHandleType = None
 #from io import IOBase
 from types import CodeType, FunctionType, MethodType, GeneratorType, \
     TracebackType, FrameType, ModuleType, BuiltinMethodType
@@ -775,6 +783,14 @@
         return typing.Tuple[()]
     return typing.Tuple[argz]
 
+if ThreadHandleType:
+    def _create_thread_handle(ident, done, *args): #XXX: ignores 'blocking'
+        from threading import _make_thread_handle
+        handle = _make_thread_handle(ident)
+        if done:
+            handle._set_done()
+        return handle
+
 def _create_lock(locked, *args): #XXX: ignores 'blocking'
     from threading import Lock
     lock = Lock()
@@ -1306,7 +1322,15 @@
         logger.trace(pickler, "# Ga2")
     return
 
-@register(LockType)
+if ThreadHandleType:
+    @register(ThreadHandleType)
+    def save_thread_handle(pickler, obj):
+        logger.trace(pickler, "Th: %s", obj)
+        pickler.save_reduce(_create_thread_handle, (obj.ident, obj.is_done()), 
obj=obj)
+        logger.trace(pickler, "# Th")
+        return
+
+@register(LockType) #XXX: copied Thread will have new Event (due to new Lock)
 def save_lock(pickler, obj):
     logger.trace(pickler, "Lo: %s", obj)
     pickler.save_reduce(_create_lock, (obj.locked(),), obj=obj)
@@ -1773,7 +1797,7 @@
         logger.trace(pickler, "# T6")
         return
 
-    # special cases: NoneType, NotImplementedType, EllipsisType, EnumMeta
+    # special caes: NoneType, NotImplementedType, EllipsisType, EnumMeta, etc
     elif obj is type(None):
         logger.trace(pickler, "T7: %s", obj)
         #XXX: pickler.save_reduce(type, (None,), obj=obj)
@@ -1791,6 +1815,10 @@
         logger.trace(pickler, "T7: %s", obj)
         pickler.write(GLOBAL + b'enum\nEnumMeta\n')
         logger.trace(pickler, "# T7")
+    elif obj is ExceptHookArgsType: #NOTE: must be after NoneType for pypy
+        logger.trace(pickler, "T7: %s", obj)
+        pickler.write(GLOBAL + b'threading\nExceptHookArgs\n')
+        logger.trace(pickler, "# T7")
 
     else:
         _byref = getattr(pickler, '_byref', None)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/dill/_objects.py 
new/dill-0.3.9/dill/_objects.py
--- old/dill-0.3.8/dill/_objects.py     2024-01-28 00:44:53.000000000 +0100
+++ new/dill-0.3.9/dill/_objects.py     2024-09-29 02:04:07.000000000 +0200
@@ -16,7 +16,7 @@
 import warnings; warnings.filterwarnings("ignore", category=DeprecationWarning)
 import sys
 import queue as Queue
-import dbm as anydbm
+#import dbm as anydbm #XXX: delete foo
 from io import BytesIO as StringIO
 import re
 import array
@@ -72,6 +72,8 @@
     HAS_CTYPES = False
     IS_PYPY = False
 
+IS_PYODIDE = sys.platform == 'emscripten'
+
 # helper objects
 class _class:
     def _method(self):
@@ -250,13 +252,15 @@
 a['SliceType'] = slice(1)
 a['UnboundMethodType'] = _class._method #XXX: works when not imported!
 d['TextWrapperType'] = open(os.devnull, 'r') # same as mode='w','w+','r+'
-d['BufferedRandomType'] = open(os.devnull, 'r+b') # same as mode='w+b'
+if not IS_PYODIDE:
+    d['BufferedRandomType'] = open(os.devnull, 'r+b') # same as mode='w+b'
 d['BufferedReaderType'] = open(os.devnull, 'rb') # (default: buffering=-1)
 d['BufferedWriterType'] = open(os.devnull, 'wb')
 try: # oddities: deprecated
     from _pyio import open as _open
     d['PyTextWrapperType'] = _open(os.devnull, 'r', buffering=-1)
-    d['PyBufferedRandomType'] = _open(os.devnull, 'r+b', buffering=-1)
+    if not IS_PYODIDE:
+        d['PyBufferedRandomType'] = _open(os.devnull, 'r+b', buffering=-1)
     d['PyBufferedReaderType'] = _open(os.devnull, 'rb', buffering=-1)
     d['PyBufferedWriterType'] = _open(os.devnull, 'wb', buffering=-1)
 except ImportError:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/dill/logger.py 
new/dill-0.3.9/dill/logger.py
--- old/dill-0.3.8/dill/logger.py       2024-01-28 00:44:53.000000000 +0100
+++ new/dill-0.3.9/dill/logger.py       2024-09-29 02:04:07.000000000 +0200
@@ -253,7 +253,7 @@
         arg: a boolean value, or an optional file-like or path-like object for 
the context manager
         mode: mode string for ``open()`` if a file name is passed as the first 
argument
     """
-    if not isinstance(arg, bool):
+    if repr(arg) not in ('False', 'True'):
         return TraceManager(file=arg, mode=mode)
     logger.setLevel(logging.INFO if arg else logging.WARNING)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/dill/session.py 
new/dill-0.3.9/dill/session.py
--- old/dill-0.3.8/dill/session.py      2024-01-28 00:44:53.000000000 +0100
+++ new/dill-0.3.9/dill/session.py      2024-09-29 02:04:07.000000000 +0200
@@ -19,22 +19,21 @@
 import os
 import sys
 import warnings
+import pathlib
+import tempfile
+
+TEMPDIR = pathlib.PurePath(tempfile.gettempdir())
+
+# Type hints.
+from typing import Optional, Union
 
 from dill import _dill, Pickler, Unpickler
 from ._dill import (
     BuiltinMethodType, FunctionType, MethodType, ModuleType, TypeType,
     _import_module, _is_builtin_module, _is_imported_module, _main_module,
-    _reverse_typemap, __builtin__,
+    _reverse_typemap, __builtin__, UnpicklingError,
 )
 
-# Type hints.
-from typing import Optional, Union
-
-import pathlib
-import tempfile
-
-TEMPDIR = pathlib.PurePath(tempfile.gettempdir())
-
 def _module_map():
     """get map of imported modules"""
     from collections import defaultdict
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/dill/source.py 
new/dill-0.3.9/dill/source.py
--- old/dill-0.3.8/dill/source.py       2024-01-28 00:44:53.000000000 +0100
+++ new/dill-0.3.9/dill/source.py       2024-09-29 02:04:07.000000000 +0200
@@ -150,7 +150,7 @@
         if err:
             raise IOError(err)
         lbuf = readline.get_current_history_length()
-        lines = [readline.get_history_item(i)+'\n' for i in range(1,lbuf)]
+        lines = [readline.get_history_item(i)+'\n' for i in range(1,lbuf+1)]
     else:
         try: # special handling for class instances
             if not isclass(object) and isclass(type(object)): # __class__
@@ -481,7 +481,8 @@
 def indent(code, spaces=4):
     '''indent a block of code with whitespace (default is 4 spaces)'''
     indent = indentsize(code)
-    if type(spaces) is int: spaces = ' '*spaces
+    from numbers import Integral
+    if isinstance(spaces, Integral): spaces = ' '*spaces
     # if '\t' is provided, will indent with a tab
     nspaces = indentsize(spaces)
     # blank lines (etc) need to be ignored
@@ -529,7 +530,7 @@
     return '\n'.join(_outdent(code.split('\n'), spaces=spaces, all=all))
 
 
-#XXX: not sure what the point of _wrap is...
+# _wrap provides an wrapper to correctly exec and load into locals
 __globals__ = globals()
 __locals__ = locals()
 def _wrap(f):
@@ -601,10 +602,13 @@
 
 def getname(obj, force=False, fqn=False): #XXX: throw(?) to raise error on 
fail?
     """get the name of the object. for lambdas, get the name of the pointer """
-    if fqn: return '.'.join(_namespace(obj))
+    if fqn: return '.'.join(_namespace(obj)) #NOTE: returns 'type'
     module = getmodule(obj)
     if not module: # things like "None" and "1"
-        if not force: return None
+        if not force: return None #NOTE: returns 'instance' NOT 'type' #FIXME?
+        # handle some special cases
+        if hasattr(obj, 'dtype') and not obj.shape:
+            return getname(obj.__class__) + "(" + repr(obj.tolist()) + ")" 
         return repr(obj)
     try:
         #XXX: 'wrong' for decorators and curried functions ?
@@ -739,6 +743,8 @@
     except Exception: # it's probably something 'importable'
         if head in ['builtins','__builtin__']:
             name = repr(obj) #XXX: catch [1,2], (1,2), set([1,2])... others?
+        elif _isinstance(obj):
+            name = getname(obj, force=True).split('(')[0]
         else:
             name = repr(obj).split('(')[0]
    #if not repr(obj).startswith('<'): name = repr(obj).split('(')[0]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/dill/tests/test_detect.py 
new/dill-0.3.9/dill/tests/test_detect.py
--- old/dill-0.3.8/dill/tests/test_detect.py    2024-01-28 00:44:53.000000000 
+0100
+++ new/dill-0.3.9/dill/tests/test_detect.py    2024-09-29 02:04:07.000000000 
+0200
@@ -29,7 +29,8 @@
     s = set([(err.__class__.__name__,err.args[0]) for err in list(errors(f, 
1).values())])
     a = dict(s)
     if not os.environ.get('COVERAGE'): #XXX: travis-ci
-        assert len(s) is len(a) # TypeError (and possibly PicklingError)
+        proxy = 0 if type(f.f_locals) is dict else 1
+        assert len(s) == len(a) + proxy # TypeError (and possibly 
PicklingError)
     n = 2
     assert len(a) is n if 'PicklingError' in a.keys() else n-1
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/dill/tests/test_selected.py 
new/dill-0.3.9/dill/tests/test_selected.py
--- old/dill-0.3.8/dill/tests/test_selected.py  2024-01-28 00:44:53.000000000 
+0100
+++ new/dill-0.3.9/dill/tests/test_selected.py  2024-09-29 02:04:07.000000000 
+0200
@@ -45,7 +45,8 @@
 # some clean-up #FIXME: should happen internal to dill
 objects['TemporaryFileType'].close()
 objects['TextWrapperType'].close()
-objects['BufferedRandomType'].close()
+if 'BufferedRandomType' in objects:
+    objects['BufferedRandomType'].close()
 objects['BufferedReaderType'].close()
 objects['BufferedWriterType'].close()
 objects['FileType'].close()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/dill/tests/test_source.py 
new/dill-0.3.9/dill/tests/test_source.py
--- old/dill-0.3.8/dill/tests/test_source.py    2024-01-28 00:44:53.000000000 
+0100
+++ new/dill-0.3.9/dill/tests/test_source.py    2024-09-29 02:04:07.000000000 
+0200
@@ -6,8 +6,8 @@
 # License: 3-clause BSD.  The full license text is available at:
 #  - https://github.com/uqfoundation/dill/blob/master/LICENSE
 
-from dill.source import getsource, getname, _wrap, likely_import
-from dill.source import getimportable
+from dill.source import getsource, getname, _wrap, getimport
+from dill.source import importable
 from dill._dill import IS_PYPY
 
 import sys
@@ -55,31 +55,31 @@
 
 # test itself
 def test_itself():
-  assert likely_import(likely_import)=='from dill.source import 
likely_import\n'
+  assert getimport(getimport)=='from dill.source import getimport\n'
 
 # builtin functions and objects
 def test_builtin():
-  assert likely_import(pow) == 'pow\n'
-  assert likely_import(100) == '100\n'
-  assert likely_import(True) == 'True\n'
-  assert likely_import(pow, explicit=True) == 'from builtins import pow\n'
-  assert likely_import(100, explicit=True) == '100\n'
-  assert likely_import(True, explicit=True) == 'True\n'
+  assert getimport(pow) == 'pow\n'
+  assert getimport(100) == '100\n'
+  assert getimport(True) == 'True\n'
+  assert getimport(pow, builtin=True) == 'from builtins import pow\n'
+  assert getimport(100, builtin=True) == '100\n'
+  assert getimport(True, builtin=True) == 'True\n'
   # this is kinda BS... you can't import a None
-  assert likely_import(None) == 'None\n'
-  assert likely_import(None, explicit=True) == 'None\n'
+  assert getimport(None) == 'None\n'
+  assert getimport(None, builtin=True) == 'None\n'
 
 
 # other imported functions
 def test_imported():
   from math import sin
-  assert likely_import(sin) == 'from math import sin\n'
+  assert getimport(sin) == 'from math import sin\n'
 
 # interactively defined functions
 def test_dynamic():
-  assert likely_import(add) == 'from %s import add\n' % __name__
+  assert getimport(add) == 'from %s import add\n' % __name__
   # interactive lambdas
-  assert likely_import(squared) == 'from %s import squared\n' % __name__
+  assert getimport(squared) == 'from %s import squared\n' % __name__
 
 # classes and class instances
 def test_classes():
@@ -88,59 +88,78 @@
   x = y if (IS_PYPY or sys.hexversion >= PY310b) else "from io import 
BytesIO\n"
   s = StringIO()
 
-  assert likely_import(StringIO) == x
-  assert likely_import(s) == y
+  assert getimport(StringIO) == x
+  assert getimport(s) == y
   # interactively defined classes and class instances
-  assert likely_import(Foo) == 'from %s import Foo\n' % __name__
-  assert likely_import(_foo) == 'from %s import Foo\n' % __name__
+  assert getimport(Foo) == 'from %s import Foo\n' % __name__
+  assert getimport(_foo) == 'from %s import Foo\n' % __name__
 
 
-# test getimportable
+# test importable
 def test_importable():
-  assert getimportable(add) == 'from %s import add\n' % __name__
-  assert getimportable(squared) == 'from %s import squared\n' % __name__
-  assert getimportable(Foo) == 'from %s import Foo\n' % __name__
-  assert getimportable(Foo.bar) == 'from %s import bar\n' % __name__
-  assert getimportable(_foo.bar) == 'from %s import bar\n' % __name__
-  assert getimportable(None) == 'None\n'
-  assert getimportable(100) == '100\n'
-
-  assert getimportable(add, byname=False) == 'def add(x,y):\n  return x+y\n'
-  assert getimportable(squared, byname=False) == 'squared = lambda x:x**2\n'
-  assert getimportable(None, byname=False) == 'None\n'
-  assert getimportable(Bar, byname=False) == 'class Bar:\n  pass\n'
-  assert getimportable(Foo, byname=False) == 'class Foo(object):\n  def 
bar(self, x):\n    return x*x+x\n'
-  assert getimportable(Foo.bar, byname=False) == 'def bar(self, x):\n  return 
x*x+x\n'
-  assert getimportable(Foo.bar, byname=True) == 'from %s import bar\n' % 
__name__
-  assert getimportable(Foo.bar, alias='memo', byname=True) == 'from %s import 
bar as memo\n' % __name__
-  assert getimportable(Foo, alias='memo', byname=True) == 'from %s import Foo 
as memo\n' % __name__
-  assert getimportable(squared, alias='memo', byname=True) == 'from %s import 
squared as memo\n' % __name__
-  assert getimportable(squared, alias='memo', byname=False) == 'memo = squared 
= lambda x:x**2\n'
-  assert getimportable(add, alias='memo', byname=False) == 'def add(x,y):\n  
return x+y\n\nmemo = add\n'
-  assert getimportable(None, alias='memo', byname=False) == 'memo = None\n'
-  assert getimportable(100, alias='memo', byname=False) == 'memo = 100\n'
-  assert getimportable(add, explicit=True) == 'from %s import add\n' % __name__
-  assert getimportable(squared, explicit=True) == 'from %s import squared\n' % 
__name__
-  assert getimportable(Foo, explicit=True) == 'from %s import Foo\n' % __name__
-  assert getimportable(Foo.bar, explicit=True) == 'from %s import bar\n' % 
__name__
-  assert getimportable(_foo.bar, explicit=True) == 'from %s import bar\n' % 
__name__
-  assert getimportable(None, explicit=True) == 'None\n'
-  assert getimportable(100, explicit=True) == '100\n'
+  assert importable(add, source=False) == 'from %s import add\n' % __name__
+  assert importable(squared, source=False) == 'from %s import squared\n' % 
__name__
+  assert importable(Foo, source=False) == 'from %s import Foo\n' % __name__
+  assert importable(Foo.bar, source=False) == 'from %s import bar\n' % __name__
+  assert importable(_foo.bar, source=False) == 'from %s import bar\n' % 
__name__
+  assert importable(None, source=False) == 'None\n'
+  assert importable(100, source=False) == '100\n'
+
+  assert importable(add, source=True) == 'def add(x,y):\n  return x+y\n'
+  assert importable(squared, source=True) == 'squared = lambda x:x**2\n'
+  assert importable(None, source=True) == 'None\n'
+  assert importable(Bar, source=True) == 'class Bar:\n  pass\n'
+  assert importable(Foo, source=True) == 'class Foo(object):\n  def bar(self, 
x):\n    return x*x+x\n'
+  assert importable(Foo.bar, source=True) == 'def bar(self, x):\n  return 
x*x+x\n'
+  assert importable(Foo.bar, source=False) == 'from %s import bar\n' % __name__
+  assert importable(Foo.bar, alias='memo', source=False) == 'from %s import 
bar as memo\n' % __name__
+  assert importable(Foo, alias='memo', source=False) == 'from %s import Foo as 
memo\n' % __name__
+  assert importable(squared, alias='memo', source=False) == 'from %s import 
squared as memo\n' % __name__
+  assert importable(squared, alias='memo', source=True) == 'memo = squared = 
lambda x:x**2\n'
+  assert importable(add, alias='memo', source=True) == 'def add(x,y):\n  
return x+y\n\nmemo = add\n'
+  assert importable(None, alias='memo', source=True) == 'memo = None\n'
+  assert importable(100, alias='memo', source=True) == 'memo = 100\n'
+  assert importable(add, builtin=True, source=False) == 'from %s import add\n' 
% __name__
+  assert importable(squared, builtin=True, source=False) == 'from %s import 
squared\n' % __name__
+  assert importable(Foo, builtin=True, source=False) == 'from %s import Foo\n' 
% __name__
+  assert importable(Foo.bar, builtin=True, source=False) == 'from %s import 
bar\n' % __name__
+  assert importable(_foo.bar, builtin=True, source=False) == 'from %s import 
bar\n' % __name__
+  assert importable(None, builtin=True, source=False) == 'None\n'
+  assert importable(100, builtin=True, source=False) == '100\n'
 
 
 def test_numpy():
   try:
-    from numpy import array
-    x = array([1,2,3])
-    assert getimportable(x) == 'from numpy import array\narray([1, 2, 3])\n'
-    assert getimportable(array) == 'from %s import array\n' % array.__module__
-    assert getimportable(x, byname=False) == 'from numpy import 
array\narray([1, 2, 3])\n'
-    assert getimportable(array, byname=False) == 'from %s import array\n' % 
array.__module__
+    import numpy as np
+    y = np.array
+    x = y([1,2,3])
+    assert importable(x, source=False) == 'from numpy import array\narray([1, 
2, 3])\n'
+    assert importable(y, source=False) == 'from %s import array\n' % 
y.__module__
+    assert importable(x, source=True) == 'from numpy import array\narray([1, 
2, 3])\n'
+    assert importable(y, source=True) == 'from %s import array\n' % 
y.__module__
+    y = np.int64
+    x = y(0)
+    assert importable(x, source=False) == 'from numpy import int64\nint64(0)\n'
+    assert importable(y, source=False) == 'from %s import int64\n' % 
y.__module__
+    assert importable(x, source=True) == 'from numpy import int64\nint64(0)\n'
+    assert importable(y, source=True) == 'from %s import int64\n' % 
y.__module__
+    y = np.bool_
+    x = y(0)
+    import warnings
+    with warnings.catch_warnings():
+        warnings.filterwarnings('ignore', category=FutureWarning)
+        warnings.filterwarnings('ignore', category=DeprecationWarning)
+        if hasattr(np, 'bool'): b = 'bool_' if np.bool is bool else 'bool'
+        else: b = 'bool_'
+    assert importable(x, source=False) == 'from numpy import %s\n%s(False)\n' 
% (b,b)
+    assert importable(y, source=False) == 'from %s import %s\n' % 
(y.__module__,b)
+    assert importable(x, source=True) == 'from numpy import %s\n%s(False)\n' % 
(b,b)
+    assert importable(y, source=True) == 'from %s import %s\n' % 
(y.__module__,b)
   except ImportError: pass
 
-#NOTE: if before likely_import(pow), will cause pow to throw AssertionError
+#NOTE: if before getimport(pow), will cause pow to throw AssertionError
 def test_foo():
-  assert getimportable(_foo, byname=False).startswith("import dill\nclass 
Foo(object):\n  def bar(self, x):\n    return x*x+x\ndill.loads(")
+  assert importable(_foo, source=True).startswith("import dill\nclass 
Foo(object):\n  def bar(self, x):\n    return x*x+x\ndill.loads(")
 
 if __name__ == '__main__':
     test_getsource()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/dill/tests/test_sources.py 
new/dill-0.3.9/dill/tests/test_sources.py
--- old/dill-0.3.8/dill/tests/test_sources.py   1970-01-01 01:00:00.000000000 
+0100
+++ new/dill-0.3.9/dill/tests/test_sources.py   2024-09-29 02:04:07.000000000 
+0200
@@ -0,0 +1,190 @@
+#!/usr/bin/env python
+#
+# Author: Mike McKerns (mmckerns @uqfoundation)
+# Copyright (c) 2024 The Uncertainty Quantification Foundation.
+# License: 3-clause BSD.  The full license text is available at:
+#  - https://github.com/uqfoundation/dill/blob/master/LICENSE
+"""
+check that dill.source performs as expected with changes to locals in 3.13.0b1
+see: https://github.com/python/cpython/issues/118888
+"""
+# repeat functions from test_source.py
+f = lambda x: x**2
+def g(x): return f(x) - x
+
+def h(x):
+  def g(x): return x
+  return g(x) - x
+
+class Foo(object):
+  def bar(self, x):
+    return x*x+x
+_foo = Foo()
+
+def add(x,y):
+  return x+y
+
+squared = lambda x:x**2
+
+class Bar:
+  pass
+_bar = Bar()
+
+# repeat, but from test_source.py
+import test_source as ts
+
+# test objects created in other test modules
+import test_mixins as tm
+
+import dill.source as ds
+
+
+def test_isfrommain():
+  assert ds.isfrommain(add) == True
+  assert ds.isfrommain(squared) == True
+  assert ds.isfrommain(Bar) == True
+  assert ds.isfrommain(_bar) == True
+  assert ds.isfrommain(ts.add) == False
+  assert ds.isfrommain(ts.squared) == False
+  assert ds.isfrommain(ts.Bar) == False
+  assert ds.isfrommain(ts._bar) == False
+  assert ds.isfrommain(tm.quad) == False
+  assert ds.isfrommain(tm.double_add) == False
+  assert ds.isfrommain(tm.quadratic) == False
+  assert ds.isdynamic(add) == False
+  assert ds.isdynamic(squared) == False
+  assert ds.isdynamic(ts.add) == False
+  assert ds.isdynamic(ts.squared) == False
+  assert ds.isdynamic(tm.double_add) == False
+  assert ds.isdynamic(tm.quadratic) == False
+
+
+def test_matchlambda():
+  assert ds._matchlambda(f, 'f = lambda x: x**2\n')
+  assert ds._matchlambda(squared, 'squared = lambda x:x**2\n')
+  assert ds._matchlambda(ts.f, 'f = lambda x: x**2\n')
+  assert ds._matchlambda(ts.squared, 'squared = lambda x:x**2\n')
+
+
+def test_findsource():
+  lines, lineno = ds.findsource(add)
+  assert lines[lineno] == 'def add(x,y):\n'
+  lines, lineno = ds.findsource(ts.add)
+  assert lines[lineno] == 'def add(x,y):\n'
+  lines, lineno = ds.findsource(squared)
+  assert lines[lineno] == 'squared = lambda x:x**2\n'
+  lines, lineno = ds.findsource(ts.squared)
+  assert lines[lineno] == 'squared = lambda x:x**2\n'
+  lines, lineno = ds.findsource(Bar)
+  assert lines[lineno] == 'class Bar:\n'
+  lines, lineno = ds.findsource(ts.Bar)
+  assert lines[lineno] == 'class Bar:\n'
+  lines, lineno = ds.findsource(_bar)
+  assert lines[lineno] == 'class Bar:\n'
+  lines, lineno = ds.findsource(ts._bar)
+  assert lines[lineno] == 'class Bar:\n'
+  lines, lineno = ds.findsource(tm.quad)
+  assert lines[lineno] == 'def quad(a=1, b=1, c=0):\n'
+  lines, lineno = ds.findsource(tm.double_add)
+  assert lines[lineno] == '    def func(*args, **kwds):\n'
+  lines, lineno = ds.findsource(tm.quadratic)
+  assert lines[lineno] == '  def dec(f):\n'
+
+
+def test_getsourcelines():
+  assert ''.join(ds.getsourcelines(add)[0]) == 'def add(x,y):\n  return x+y\n'
+  assert ''.join(ds.getsourcelines(ts.add)[0]) == 'def add(x,y):\n  return 
x+y\n'
+  assert ''.join(ds.getsourcelines(squared)[0]) == 'squared = lambda x:x**2\n'
+  assert ''.join(ds.getsourcelines(ts.squared)[0]) == 'squared = lambda 
x:x**2\n'
+  assert ''.join(ds.getsourcelines(Bar)[0]) == 'class Bar:\n  pass\n'
+  assert ''.join(ds.getsourcelines(ts.Bar)[0]) == 'class Bar:\n  pass\n'
+  assert ''.join(ds.getsourcelines(_bar)[0]) == 'class Bar:\n  pass\n' #XXX: ?
+  assert ''.join(ds.getsourcelines(ts._bar)[0]) == 'class Bar:\n  pass\n' 
#XXX: ?
+  assert ''.join(ds.getsourcelines(tm.quad)[0]) == 'def quad(a=1, b=1, c=0):\n 
 inverted = [False]\n  def invert():\n    inverted[0] = not inverted[0]\n  def 
dec(f):\n    def func(*args, **kwds):\n      x = f(*args, **kwds)\n      if 
inverted[0]: x = -x\n      return a*x**2 + b*x + c\n    func.__wrapped__ = f\n  
  func.invert = invert\n    func.inverted = inverted\n    return func\n  return 
dec\n'
+  assert ''.join(ds.getsourcelines(tm.quadratic)[0]) == '  def dec(f):\n    
def func(*args,**kwds):\n      fx = f(*args,**kwds)\n      return a*fx**2 + 
b*fx + c\n    return func\n'
+  assert ''.join(ds.getsourcelines(tm.quadratic, lstrip=True)[0]) == 'def 
dec(f):\n  def func(*args,**kwds):\n    fx = f(*args,**kwds)\n    return 
a*fx**2 + b*fx + c\n  return func\n'
+  assert ''.join(ds.getsourcelines(tm.quadratic, enclosing=True)[0]) == 'def 
quad_factory(a=1,b=1,c=0):\n  def dec(f):\n    def func(*args,**kwds):\n      
fx = f(*args,**kwds)\n      return a*fx**2 + b*fx + c\n    return func\n  
return dec\n'
+  assert ''.join(ds.getsourcelines(tm.double_add)[0]) == '    def func(*args, 
**kwds):\n      x = f(*args, **kwds)\n      if inverted[0]: x = -x\n      
return a*x**2 + b*x + c\n'
+  assert ''.join(ds.getsourcelines(tm.double_add, enclosing=True)[0]) == 'def 
quad(a=1, b=1, c=0):\n  inverted = [False]\n  def invert():\n    inverted[0] = 
not inverted[0]\n  def dec(f):\n    def func(*args, **kwds):\n      x = 
f(*args, **kwds)\n      if inverted[0]: x = -x\n      return a*x**2 + b*x + c\n 
   func.__wrapped__ = f\n    func.invert = invert\n    func.inverted = 
inverted\n    return func\n  return dec\n'
+
+
+def test_indent():
+  assert ds.outdent(''.join(ds.getsourcelines(tm.quadratic)[0])) == 
''.join(ds.getsourcelines(tm.quadratic, lstrip=True)[0])
+  assert ds.indent(''.join(ds.getsourcelines(tm.quadratic, lstrip=True)[0]), 
2) == ''.join(ds.getsourcelines(tm.quadratic)[0])
+
+
+def test_dumpsource():
+  local = {}
+  exec(ds.dumpsource(add, alias='raw'), {}, local)
+  exec(ds.dumpsource(ts.add, alias='mod'), {}, local)
+  assert local['raw'](1,2) == local['mod'](1,2)
+  exec(ds.dumpsource(squared, alias='raw'), {}, local)
+  exec(ds.dumpsource(ts.squared, alias='mod'), {}, local)
+  assert local['raw'](3) == local['mod'](3)
+  assert ds._wrap(add)(1,2) == ds._wrap(ts.add)(1,2)
+  assert ds._wrap(squared)(3) == ds._wrap(ts.squared)(3)
+
+
+def test_name():
+  assert ds._namespace(add) == ds.getname(add, fqn=True).split('.')
+  assert ds._namespace(ts.add) == ds.getname(ts.add, fqn=True).split('.')
+  assert ds._namespace(squared) == ds.getname(squared, fqn=True).split('.')
+  assert ds._namespace(ts.squared) == ds.getname(ts.squared, 
fqn=True).split('.')
+  assert ds._namespace(Bar) == ds.getname(Bar, fqn=True).split('.')
+  assert ds._namespace(ts.Bar) == ds.getname(ts.Bar, fqn=True).split('.')
+  assert ds._namespace(tm.quad) == ds.getname(tm.quad, fqn=True).split('.')
+  #XXX: the following also works, however behavior may be wrong for nested 
functions
+  #assert ds._namespace(tm.double_add) == ds.getname(tm.double_add, 
fqn=True).split('.')
+  #assert ds._namespace(tm.quadratic) == ds.getname(tm.quadratic, 
fqn=True).split('.')
+  assert ds.getname(add) == 'add'
+  assert ds.getname(ts.add) == 'add'
+  assert ds.getname(squared) == 'squared'
+  assert ds.getname(ts.squared) == 'squared'
+  assert ds.getname(Bar) == 'Bar'
+  assert ds.getname(ts.Bar) == 'Bar'
+  assert ds.getname(tm.quad) == 'quad'
+  assert ds.getname(tm.double_add) == 'func' #XXX: ?
+  assert ds.getname(tm.quadratic) == 'dec' #XXX: ?
+
+
+def test_getimport():
+  local = {}
+  exec(ds.getimport(add, alias='raw'), {}, local)
+  exec(ds.getimport(ts.add, alias='mod'), {}, local)
+  assert local['raw'](1,2) == local['mod'](1,2)
+  exec(ds.getimport(squared, alias='raw'), {}, local)
+  exec(ds.getimport(ts.squared, alias='mod'), {}, local)
+  assert local['raw'](3) == local['mod'](3)
+  exec(ds.getimport(Bar, alias='raw'), {}, local)
+  exec(ds.getimport(ts.Bar, alias='mod'), {}, local)
+  assert ds.getname(local['raw']) == ds.getname(local['mod'])
+  exec(ds.getimport(tm.quad, alias='mod'), {}, local)
+  assert local['mod']()(sum)([1,2,3]) == tm.quad()(sum)([1,2,3])
+  #FIXME: wrong results for nested functions (e.g. tm.double_add, tm.quadratic)
+
+
+def test_importable():
+  assert ds.importable(add, source=False) == ds.getimport(add)
+  assert ds.importable(add) == ds.getsource(add)
+  assert ds.importable(squared, source=False) == ds.getimport(squared)
+  assert ds.importable(squared) == ds.getsource(squared)
+  assert ds.importable(Bar, source=False) == ds.getimport(Bar)
+  assert ds.importable(Bar) == ds.getsource(Bar)
+  assert ds.importable(ts.add) == ds.getimport(ts.add)
+  assert ds.importable(ts.add, source=True) == ds.getsource(ts.add)
+  assert ds.importable(ts.squared) == ds.getimport(ts.squared)
+  assert ds.importable(ts.squared, source=True) == ds.getsource(ts.squared)
+  assert ds.importable(ts.Bar) == ds.getimport(ts.Bar)
+  assert ds.importable(ts.Bar, source=True) == ds.getsource(ts.Bar)
+
+
+if __name__ == '__main__':
+  test_isfrommain()
+  test_matchlambda()
+  test_findsource()
+  test_getsourcelines()
+  test_indent()
+  test_dumpsource()
+  test_name()
+  test_getimport()
+  test_importable()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/dill/tests/test_threads.py 
new/dill-0.3.9/dill/tests/test_threads.py
--- old/dill-0.3.8/dill/tests/test_threads.py   1970-01-01 01:00:00.000000000 
+0100
+++ new/dill-0.3.9/dill/tests/test_threads.py   2024-09-29 02:04:07.000000000 
+0200
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+#
+# Author: Mike McKerns (mmckerns @caltech and @uqfoundation)
+# Copyright (c) 2024 The Uncertainty Quantification Foundation.
+# License: 3-clause BSD.  The full license text is available at:
+#  - https://github.com/uqfoundation/dill/blob/master/LICENSE
+
+import dill
+dill.settings['recurse'] = True
+
+
+def test_new_thread():
+    import threading
+    t = threading.Thread()
+    t_ = dill.copy(t)
+    assert t.is_alive() == t_.is_alive()
+    for i in ['daemon','name','ident','native_id']:
+        if hasattr(t, i):
+            assert getattr(t, i) == getattr(t_, i)
+
+def test_run_thread():
+    import threading
+    t = threading.Thread()
+    t.start()
+    t_ = dill.copy(t)
+    assert t.is_alive() == t_.is_alive()
+    for i in ['daemon','name','ident','native_id']:
+        if hasattr(t, i):
+            assert getattr(t, i) == getattr(t_, i)
+
+def test_join_thread():
+    import threading
+    t = threading.Thread()
+    t.start()
+    t.join()
+    t_ = dill.copy(t)
+    assert t.is_alive() == t_.is_alive()
+    for i in ['daemon','name','ident','native_id']:
+        if hasattr(t, i):
+            assert getattr(t, i) == getattr(t_, i)
+
+
+if __name__ == '__main__':
+    test_new_thread()
+    test_run_thread()
+    test_join_thread()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/docs/requirements.txt 
new/dill-0.3.9/docs/requirements.txt
--- old/dill-0.3.8/docs/requirements.txt        2024-01-28 00:44:53.000000000 
+0100
+++ new/dill-0.3.9/docs/requirements.txt        2024-09-29 02:04:07.000000000 
+0200
@@ -1,40 +1,56 @@
 # Packages required to build docs
 # dependencies pinned as:
-# 
https://github.com/readthedocs/readthedocs.org/blob/4dd655eaa5a36aa2cb9eed3e98961419536f99e8/requirements/docs.txt
+# 
https://github.com/readthedocs/readthedocs.org/blob/d3606da9907bb4cd933abcf71c7bab9eb20435cd/requirements/docs.txt
 
-alabaster==0.7.13
-babel==2.12.1
-certifi==2023.7.22
-charset-normalizer==3.2.0
-click==8.1.6
+alabaster==0.7.16
+anyio==4.4.0
+babel==2.15.0
+certifi==2024.7.4
+charset-normalizer==3.3.2
+click==8.1.7
 colorama==0.4.6
-docutils==0.18.1
-idna==3.4
+docutils==0.20.1
+exceptiongroup==1.2.1
+h11==0.14.0
+idna==3.7
 imagesize==1.4.1
-jinja2==3.1.3
-livereload==2.6.3
+jinja2==3.1.4
 markdown-it-py==3.0.0
-markupsafe==2.1.3
-mdit-py-plugins==0.4.0
+markupsafe==2.1.5
+mdit-py-plugins==0.4.1
 mdurl==0.1.2
-myst-parser==2.0.0
-packaging==23.1
-pygments==2.16.1
+myst-parser==3.0.1
+packaging==24.0
+pygments==2.18.0
 pyyaml==6.0.1
 readthedocs-sphinx-search==0.3.2
-requests==2.31.0
+requests==2.32.3
 six==1.16.0
+sniffio==1.3.1
 snowballstemmer==2.2.0
-sphinx==6.2.1
-sphinx-autobuild==2021.3.14
+sphinx==7.3.7
+sphinx-autobuild==2024.4.16
 sphinx-copybutton==0.5.2
-sphinx-design==0.5.0
-sphinx-hoverxref==1.3.0
-sphinx-intl==2.1.0
+sphinx-design==0.6.0
+sphinx-hoverxref==1.4.0
+sphinx-intl==2.2.0
 sphinx-multiproject==1.0.0rc1
-sphinx-notfound-page==0.8.3
-sphinx-prompt==1.6.0
-sphinx-rtd-theme==1.2.2
-sphinx-tabs==3.4.1
-tornado==6.3.3
-urllib3==2.0.7
+sphinx-notfound-page==1.0.2
+sphinx-prompt==1.8.0
+sphinx-rtd-theme==2.0.0rc2
+sphinx-tabs==3.4.5
+sphinxcontrib-applehelp==1.0.8
+sphinxcontrib-devhelp==1.0.6
+sphinxcontrib-htmlhelp==2.0.5
+sphinxcontrib-httpdomain==1.8.1
+sphinxcontrib-jquery==4.1
+sphinxcontrib-jsmath==1.0.1
+sphinxcontrib-qthelp==1.0.7
+sphinxcontrib-serializinghtml==1.1.10
+starlette==0.37.2
+tomli==2.0.1
+typing-extensions==4.12.1
+urllib3==2.2.2
+uvicorn==0.30.0
+watchfiles==0.22.0
+websockets==12.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/setup.cfg new/dill-0.3.9/setup.cfg
--- old/dill-0.3.8/setup.cfg    2024-01-28 00:44:53.000000000 +0100
+++ new/dill-0.3.9/setup.cfg    2024-09-29 02:04:07.000000000 +0200
@@ -3,7 +3,7 @@
 
 [bdist_wheel]
 #python-tag = py3
-#plat-name = manylinux_2_24_x86_64
+#plat-name = manylinux_2_28_x86_64
 
 [sdist]
 #formats=zip,gztar
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/setup.py new/dill-0.3.9/setup.py
--- old/dill-0.3.8/setup.py     2024-01-28 00:44:53.000000000 +0100
+++ new/dill-0.3.9/setup.py     2024-09-29 02:04:07.000000000 +0200
@@ -67,6 +67,7 @@
         'Programming Language :: Python :: 3.10',
         'Programming Language :: Python :: 3.11',
         'Programming Language :: Python :: 3.12',
+        'Programming Language :: Python :: 3.13',
         'Programming Language :: Python :: Implementation :: CPython',
         'Programming Language :: Python :: Implementation :: PyPy',
         'Topic :: Scientific/Engineering',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dill-0.3.8/version.py new/dill-0.3.9/version.py
--- old/dill-0.3.8/version.py   2024-01-28 00:44:53.000000000 +0100
+++ new/dill-0.3.9/version.py   2024-09-29 02:04:07.000000000 +0200
@@ -5,7 +5,7 @@
 # License: 3-clause BSD.  The full license text is available at:
 #  - https://github.com/uqfoundation/dill/blob/master/LICENSE
 
-__version__ = '0.3.8'#.dev0'
+__version__ = '0.3.9'#.dev0'
 __author__ = 'Mike McKerns'
 __contact__ = '[email protected]'
 

Reply via email to