test_sources.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #!/usr/bin/env python
  2. #
  3. # Author: Mike McKerns (mmckerns @uqfoundation)
  4. # Copyright (c) 2024 The Uncertainty Quantification Foundation.
  5. # License: 3-clause BSD. The full license text is available at:
  6. # - https://github.com/uqfoundation/dill/blob/master/LICENSE
  7. """
  8. check that dill.source performs as expected with changes to locals in 3.13.0b1
  9. see: https://github.com/python/cpython/issues/118888
  10. """
  11. # repeat functions from test_source.py
  12. f = lambda x: x**2
  13. def g(x): return f(x) - x
  14. def h(x):
  15. def g(x): return x
  16. return g(x) - x
  17. class Foo(object):
  18. def bar(self, x):
  19. return x*x+x
  20. _foo = Foo()
  21. def add(x,y):
  22. return x+y
  23. squared = lambda x:x**2
  24. class Bar:
  25. pass
  26. _bar = Bar()
  27. # repeat, but from test_source.py
  28. import test_source as ts
  29. # test objects created in other test modules
  30. import test_mixins as tm
  31. import dill.source as ds
  32. def test_isfrommain():
  33. assert ds.isfrommain(add) == True
  34. assert ds.isfrommain(squared) == True
  35. assert ds.isfrommain(Bar) == True
  36. assert ds.isfrommain(_bar) == True
  37. assert ds.isfrommain(ts.add) == False
  38. assert ds.isfrommain(ts.squared) == False
  39. assert ds.isfrommain(ts.Bar) == False
  40. assert ds.isfrommain(ts._bar) == False
  41. assert ds.isfrommain(tm.quad) == False
  42. assert ds.isfrommain(tm.double_add) == False
  43. assert ds.isfrommain(tm.quadratic) == False
  44. assert ds.isdynamic(add) == False
  45. assert ds.isdynamic(squared) == False
  46. assert ds.isdynamic(ts.add) == False
  47. assert ds.isdynamic(ts.squared) == False
  48. assert ds.isdynamic(tm.double_add) == False
  49. assert ds.isdynamic(tm.quadratic) == False
  50. def test_matchlambda():
  51. assert ds._matchlambda(f, 'f = lambda x: x**2\n')
  52. assert ds._matchlambda(squared, 'squared = lambda x:x**2\n')
  53. assert ds._matchlambda(ts.f, 'f = lambda x: x**2\n')
  54. assert ds._matchlambda(ts.squared, 'squared = lambda x:x**2\n')
  55. def test_findsource():
  56. lines, lineno = ds.findsource(add)
  57. assert lines[lineno] == 'def add(x,y):\n'
  58. lines, lineno = ds.findsource(ts.add)
  59. assert lines[lineno] == 'def add(x,y):\n'
  60. lines, lineno = ds.findsource(squared)
  61. assert lines[lineno] == 'squared = lambda x:x**2\n'
  62. lines, lineno = ds.findsource(ts.squared)
  63. assert lines[lineno] == 'squared = lambda x:x**2\n'
  64. lines, lineno = ds.findsource(Bar)
  65. assert lines[lineno] == 'class Bar:\n'
  66. lines, lineno = ds.findsource(ts.Bar)
  67. assert lines[lineno] == 'class Bar:\n'
  68. lines, lineno = ds.findsource(_bar)
  69. assert lines[lineno] == 'class Bar:\n'
  70. lines, lineno = ds.findsource(ts._bar)
  71. assert lines[lineno] == 'class Bar:\n'
  72. lines, lineno = ds.findsource(tm.quad)
  73. assert lines[lineno] == 'def quad(a=1, b=1, c=0):\n'
  74. lines, lineno = ds.findsource(tm.double_add)
  75. assert lines[lineno] == ' def func(*args, **kwds):\n'
  76. lines, lineno = ds.findsource(tm.quadratic)
  77. assert lines[lineno] == ' def dec(f):\n'
  78. def test_getsourcelines():
  79. assert ''.join(ds.getsourcelines(add)[0]) == 'def add(x,y):\n return x+y\n'
  80. assert ''.join(ds.getsourcelines(ts.add)[0]) == 'def add(x,y):\n return x+y\n'
  81. assert ''.join(ds.getsourcelines(squared)[0]) == 'squared = lambda x:x**2\n'
  82. assert ''.join(ds.getsourcelines(ts.squared)[0]) == 'squared = lambda x:x**2\n'
  83. assert ''.join(ds.getsourcelines(Bar)[0]) == 'class Bar:\n pass\n'
  84. assert ''.join(ds.getsourcelines(ts.Bar)[0]) == 'class Bar:\n pass\n'
  85. assert ''.join(ds.getsourcelines(_bar)[0]) == 'class Bar:\n pass\n' #XXX: ?
  86. assert ''.join(ds.getsourcelines(ts._bar)[0]) == 'class Bar:\n pass\n' #XXX: ?
  87. 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'
  88. 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'
  89. 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'
  90. 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'
  91. 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'
  92. 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'
  93. def test_indent():
  94. assert ds.outdent(''.join(ds.getsourcelines(tm.quadratic)[0])) == ''.join(ds.getsourcelines(tm.quadratic, lstrip=True)[0])
  95. assert ds.indent(''.join(ds.getsourcelines(tm.quadratic, lstrip=True)[0]), 2) == ''.join(ds.getsourcelines(tm.quadratic)[0])
  96. def test_dumpsource():
  97. local = {}
  98. exec(ds.dumpsource(add, alias='raw'), {}, local)
  99. exec(ds.dumpsource(ts.add, alias='mod'), {}, local)
  100. assert local['raw'](1,2) == local['mod'](1,2)
  101. exec(ds.dumpsource(squared, alias='raw'), {}, local)
  102. exec(ds.dumpsource(ts.squared, alias='mod'), {}, local)
  103. assert local['raw'](3) == local['mod'](3)
  104. assert ds._wrap(add)(1,2) == ds._wrap(ts.add)(1,2)
  105. assert ds._wrap(squared)(3) == ds._wrap(ts.squared)(3)
  106. def test_name():
  107. assert ds._namespace(add) == ds.getname(add, fqn=True).split('.')
  108. assert ds._namespace(ts.add) == ds.getname(ts.add, fqn=True).split('.')
  109. assert ds._namespace(squared) == ds.getname(squared, fqn=True).split('.')
  110. assert ds._namespace(ts.squared) == ds.getname(ts.squared, fqn=True).split('.')
  111. assert ds._namespace(Bar) == ds.getname(Bar, fqn=True).split('.')
  112. assert ds._namespace(ts.Bar) == ds.getname(ts.Bar, fqn=True).split('.')
  113. assert ds._namespace(tm.quad) == ds.getname(tm.quad, fqn=True).split('.')
  114. #XXX: the following also works, however behavior may be wrong for nested functions
  115. #assert ds._namespace(tm.double_add) == ds.getname(tm.double_add, fqn=True).split('.')
  116. #assert ds._namespace(tm.quadratic) == ds.getname(tm.quadratic, fqn=True).split('.')
  117. assert ds.getname(add) == 'add'
  118. assert ds.getname(ts.add) == 'add'
  119. assert ds.getname(squared) == 'squared'
  120. assert ds.getname(ts.squared) == 'squared'
  121. assert ds.getname(Bar) == 'Bar'
  122. assert ds.getname(ts.Bar) == 'Bar'
  123. assert ds.getname(tm.quad) == 'quad'
  124. assert ds.getname(tm.double_add) == 'func' #XXX: ?
  125. assert ds.getname(tm.quadratic) == 'dec' #XXX: ?
  126. def test_getimport():
  127. local = {}
  128. exec(ds.getimport(add, alias='raw'), {}, local)
  129. exec(ds.getimport(ts.add, alias='mod'), {}, local)
  130. assert local['raw'](1,2) == local['mod'](1,2)
  131. exec(ds.getimport(squared, alias='raw'), {}, local)
  132. exec(ds.getimport(ts.squared, alias='mod'), {}, local)
  133. assert local['raw'](3) == local['mod'](3)
  134. exec(ds.getimport(Bar, alias='raw'), {}, local)
  135. exec(ds.getimport(ts.Bar, alias='mod'), {}, local)
  136. assert ds.getname(local['raw']) == ds.getname(local['mod'])
  137. exec(ds.getimport(tm.quad, alias='mod'), {}, local)
  138. assert local['mod']()(sum)([1,2,3]) == tm.quad()(sum)([1,2,3])
  139. #FIXME: wrong results for nested functions (e.g. tm.double_add, tm.quadratic)
  140. def test_importable():
  141. assert ds.importable(add, source=False) == ds.getimport(add)
  142. assert ds.importable(add) == ds.getsource(add)
  143. assert ds.importable(squared, source=False) == ds.getimport(squared)
  144. assert ds.importable(squared) == ds.getsource(squared)
  145. assert ds.importable(Bar, source=False) == ds.getimport(Bar)
  146. assert ds.importable(Bar) == ds.getsource(Bar)
  147. assert ds.importable(ts.add) == ds.getimport(ts.add)
  148. assert ds.importable(ts.add, source=True) == ds.getsource(ts.add)
  149. assert ds.importable(ts.squared) == ds.getimport(ts.squared)
  150. assert ds.importable(ts.squared, source=True) == ds.getsource(ts.squared)
  151. assert ds.importable(ts.Bar) == ds.getimport(ts.Bar)
  152. assert ds.importable(ts.Bar, source=True) == ds.getsource(ts.Bar)
  153. if __name__ == '__main__':
  154. test_isfrommain()
  155. test_matchlambda()
  156. test_findsource()
  157. test_getsourcelines()
  158. test_indent()
  159. test_dumpsource()
  160. test_name()
  161. test_getimport()
  162. test_importable()