sciris 3.2.6__tar.gz → 3.2.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (457) hide show
  1. {sciris-3.2.6 → sciris-3.2.8}/.github/workflows/schedule_tests.yaml +1 -1
  2. {sciris-3.2.6 → sciris-3.2.8}/CHANGELOG.rst +9 -0
  3. {sciris-3.2.6/sciris.egg-info → sciris-3.2.8}/PKG-INFO +1 -1
  4. sciris-3.2.8/context7.json +4 -0
  5. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_asd.py +185 -128
  6. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_odict.py +25 -25
  7. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_profiling.py +15 -3
  8. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_version.py +2 -2
  9. {sciris-3.2.6 → sciris-3.2.8/sciris.egg-info}/PKG-INFO +1 -1
  10. {sciris-3.2.6 → sciris-3.2.8}/sciris.egg-info/SOURCES.txt +1 -0
  11. {sciris-3.2.6 → sciris-3.2.8}/tests/test_odict.py +1 -1
  12. {sciris-3.2.6 → sciris-3.2.8}/.github/workflows/pypi_release.yaml +0 -0
  13. {sciris-3.2.6 → sciris-3.2.8}/.github/workflows/test_downstream.yaml +0 -0
  14. {sciris-3.2.6 → sciris-3.2.8}/.github/workflows/test_sciris.yaml +0 -0
  15. {sciris-3.2.6 → sciris-3.2.8}/.gitignore +0 -0
  16. {sciris-3.2.6 → sciris-3.2.8}/.pylintrc +0 -0
  17. {sciris-3.2.6 → sciris-3.2.8}/.readthedocs.yaml +0 -0
  18. {sciris-3.2.6 → sciris-3.2.8}/CLAUDE.md +0 -0
  19. {sciris-3.2.6 → sciris-3.2.8}/CODE_OF_CONDUCT.rst +0 -0
  20. {sciris-3.2.6 → sciris-3.2.8}/CONTRIBUTING.rst +0 -0
  21. {sciris-3.2.6 → sciris-3.2.8}/LICENSE +0 -0
  22. {sciris-3.2.6 → sciris-3.2.8}/MANIFEST.in +0 -0
  23. {sciris-3.2.6 → sciris-3.2.8}/README.rst +0 -0
  24. {sciris-3.2.6 → sciris-3.2.8}/STYLE_GUIDE.rst +0 -0
  25. {sciris-3.2.6 → sciris-3.2.8}/docs/.gitignore +0 -0
  26. {sciris-3.2.6 → sciris-3.2.8}/docs/Makefile +0 -0
  27. {sciris-3.2.6 → sciris-3.2.8}/docs/README.md +0 -0
  28. {sciris-3.2.6 → sciris-3.2.8}/docs/_build/html/_static/scripts/bootstrap.js.LICENSE.txt +0 -0
  29. {sciris-3.2.6 → sciris-3.2.8}/docs/_build/html/_static/scripts/fontawesome.js.LICENSE.txt +0 -0
  30. {sciris-3.2.6 → sciris-3.2.8}/docs/_static/theme_overrides.css +0 -0
  31. {sciris-3.2.6 → sciris-3.2.8}/docs/_templates/custom-class-template.rst +0 -0
  32. {sciris-3.2.6 → sciris-3.2.8}/docs/_templates/custom-function-template.rst +0 -0
  33. {sciris-3.2.6 → sciris-3.2.8}/docs/_templates/custom-module-template.rst +0 -0
  34. {sciris-3.2.6 → sciris-3.2.8}/docs/_templates/footer.html +0 -0
  35. {sciris-3.2.6 → sciris-3.2.8}/docs/_templates/page.html +0 -0
  36. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.rst +0 -0
  37. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_asd.asd.rst +0 -0
  38. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_asd.rst +0 -0
  39. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.alpinecolormap.rst +0 -0
  40. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.arraycolors.rst +0 -0
  41. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.bandedcolormap.rst +0 -0
  42. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.bicolormap.rst +0 -0
  43. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.colormapdemo.rst +0 -0
  44. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.gridcolors.rst +0 -0
  45. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.hex2rgb.rst +0 -0
  46. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.hsv2rgb.rst +0 -0
  47. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.manualcolorbar.rst +0 -0
  48. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.midpointnorm.rst +0 -0
  49. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.orangebluecolormap.rst +0 -0
  50. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.parulacolormap.rst +0 -0
  51. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.rgb2hex.rst +0 -0
  52. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.rgb2hsv.rst +0 -0
  53. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.rst +0 -0
  54. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.sanitizecolor.rst +0 -0
  55. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.shifthue.rst +0 -0
  56. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.turbocolormap.rst +0 -0
  57. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_colors.vectocolor.rst +0 -0
  58. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_dataframe.dataframe.rst +0 -0
  59. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_dataframe.rst +0 -0
  60. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.Timer.rst +0 -0
  61. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.date.rst +0 -0
  62. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.datedelta.rst +0 -0
  63. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.daterange.rst +0 -0
  64. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.datetoyear.rst +0 -0
  65. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.day.rst +0 -0
  66. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.daydiff.rst +0 -0
  67. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.elapsedtimestr.rst +0 -0
  68. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.getdate.rst +0 -0
  69. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.now.rst +0 -0
  70. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.randsleep.rst +0 -0
  71. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.readdate.rst +0 -0
  72. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.rst +0 -0
  73. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.tic.rst +0 -0
  74. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.time.rst +0 -0
  75. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.timedsleep.rst +0 -0
  76. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.timer.rst +0 -0
  77. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.toc.rst +0 -0
  78. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.toctic.rst +0 -0
  79. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_datetime.yeartodate.rst +0 -0
  80. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.Blobject.rst +0 -0
  81. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.Failed.rst +0 -0
  82. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.Spreadsheet.rst +0 -0
  83. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.UnpicklingError.rst +0 -0
  84. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.UnpicklingWarning.rst +0 -0
  85. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.dumpstr.rst +0 -0
  86. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.getfilelist.rst +0 -0
  87. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.getfilepaths.rst +0 -0
  88. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.glob.rst +0 -0
  89. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.ispath.rst +0 -0
  90. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.jsonify.rst +0 -0
  91. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.jsonpickle.rst +0 -0
  92. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.jsonunpickle.rst +0 -0
  93. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.load.rst +0 -0
  94. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.loadany.rst +0 -0
  95. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.loadjson.rst +0 -0
  96. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.loadobj.rst +0 -0
  97. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.loadspreadsheet.rst +0 -0
  98. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.loadstr.rst +0 -0
  99. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.loadtext.rst +0 -0
  100. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.loadyaml.rst +0 -0
  101. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.loadzip.rst +0 -0
  102. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.makefilepath.rst +0 -0
  103. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.makepath.rst +0 -0
  104. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.path.rst +0 -0
  105. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.printjson.rst +0 -0
  106. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.readjson.rst +0 -0
  107. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.readyaml.rst +0 -0
  108. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.rmpath.rst +0 -0
  109. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.rst +0 -0
  110. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.sanitizefilename.rst +0 -0
  111. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.sanitizejson.rst +0 -0
  112. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.sanitizepath.rst +0 -0
  113. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.save.rst +0 -0
  114. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.savejson.rst +0 -0
  115. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.saveobj.rst +0 -0
  116. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.savespreadsheet.rst +0 -0
  117. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.savetext.rst +0 -0
  118. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.saveyaml.rst +0 -0
  119. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.savezip.rst +0 -0
  120. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.thisdir.rst +0 -0
  121. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.thisfile.rst +0 -0
  122. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.thispath.rst +0 -0
  123. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.unzip.rst +0 -0
  124. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_fileio.zsave.rst +0 -0
  125. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.approx.rst +0 -0
  126. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.cat.rst +0 -0
  127. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.convolve.rst +0 -0
  128. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.count.rst +0 -0
  129. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.dataindex.rst +0 -0
  130. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.fillnans.rst +0 -0
  131. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.findfirst.rst +0 -0
  132. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.findinds.rst +0 -0
  133. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.findlast.rst +0 -0
  134. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.findnans.rst +0 -0
  135. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.findnearest.rst +0 -0
  136. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.gauss1d.rst +0 -0
  137. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.gauss2d.rst +0 -0
  138. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.getvaliddata.rst +0 -0
  139. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.getvalidinds.rst +0 -0
  140. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.inclusiverange.rst +0 -0
  141. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.isprime.rst +0 -0
  142. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.linregress.rst +0 -0
  143. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.nanequal.rst +0 -0
  144. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.normalize.rst +0 -0
  145. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.normsum.rst +0 -0
  146. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.numdigits.rst +0 -0
  147. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.perturb.rst +0 -0
  148. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.randround.rst +0 -0
  149. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.rmnans.rst +0 -0
  150. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.rolling.rst +0 -0
  151. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.rst +0 -0
  152. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.safedivide.rst +0 -0
  153. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.sanitize.rst +0 -0
  154. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.sem.rst +0 -0
  155. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.similarity.rst +0 -0
  156. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.smooth.rst +0 -0
  157. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_math.smoothinterp.rst +0 -0
  158. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_nested.Equal.rst +0 -0
  159. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_nested.IterObj.rst +0 -0
  160. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_nested.equal.rst +0 -0
  161. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_nested.flattendict.rst +0 -0
  162. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_nested.getnested.rst +0 -0
  163. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_nested.iternested.rst +0 -0
  164. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_nested.iterobj.rst +0 -0
  165. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_nested.makenested.rst +0 -0
  166. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_nested.mergenested.rst +0 -0
  167. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_nested.nestedloop.rst +0 -0
  168. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_nested.rst +0 -0
  169. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_nested.search.rst +0 -0
  170. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_nested.setnested.rst +0 -0
  171. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_odict.argparse.rst +0 -0
  172. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_odict.asobj.rst +0 -0
  173. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_odict.counter.rst +0 -0
  174. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_odict.ddict.rst +0 -0
  175. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_odict.dictobj.rst +0 -0
  176. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_odict.objdict.rst +0 -0
  177. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_odict.odict.rst +0 -0
  178. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_odict.rst +0 -0
  179. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_parallel.Parallel.rst +0 -0
  180. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_parallel.cpu_count.rst +0 -0
  181. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_parallel.cpuload.rst +0 -0
  182. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_parallel.loadbalancer.rst +0 -0
  183. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_parallel.memload.rst +0 -0
  184. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_parallel.parallelize.rst +0 -0
  185. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_parallel.rst +0 -0
  186. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.SIticks.rst +0 -0
  187. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.ScirisDateFormatter.rst +0 -0
  188. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.animation.rst +0 -0
  189. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.ax3d.rst +0 -0
  190. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.bar3d.rst +0 -0
  191. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.boxoff.rst +0 -0
  192. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.commaticks.rst +0 -0
  193. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.dateformatter.rst +0 -0
  194. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.datenumformatter.rst +0 -0
  195. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.emptyfig.rst +0 -0
  196. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.fig3d.rst +0 -0
  197. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.figlayout.rst +0 -0
  198. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.fonts.rst +0 -0
  199. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.get_rows_cols.rst +0 -0
  200. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.getrowscols.rst +0 -0
  201. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.loadfig.rst +0 -0
  202. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.maximize.rst +0 -0
  203. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.movelegend.rst +0 -0
  204. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.orderlegend.rst +0 -0
  205. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.plot3d.rst +0 -0
  206. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.rst +0 -0
  207. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.savefig.rst +0 -0
  208. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.savefigs.rst +0 -0
  209. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.savemovie.rst +0 -0
  210. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.scatter3d.rst +0 -0
  211. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.separatelegend.rst +0 -0
  212. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.setaxislim.rst +0 -0
  213. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.setxlim.rst +0 -0
  214. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.setylim.rst +0 -0
  215. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.stackedbar.rst +0 -0
  216. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_plotting.surf3d.rst +0 -0
  217. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.arraymean.rst +0 -0
  218. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.arraymedian.rst +0 -0
  219. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.blank.rst +0 -0
  220. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.capture.rst +0 -0
  221. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.classatt.rst +0 -0
  222. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.colorize.rst +0 -0
  223. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.createcollist.rst +0 -0
  224. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.heading.rst +0 -0
  225. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.humanize_bytes.rst +0 -0
  226. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.indent.rst +0 -0
  227. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.objatt.rst +0 -0
  228. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.objectid.rst +0 -0
  229. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.objmeth.rst +0 -0
  230. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.objprop.rst +0 -0
  231. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.objrepr.rst +0 -0
  232. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.percentcomplete.rst +0 -0
  233. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.pr.rst +0 -0
  234. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.prepr.rst +0 -0
  235. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.prettyobj.rst +0 -0
  236. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.printarr.rst +0 -0
  237. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.printblue.rst +0 -0
  238. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.printcyan.rst +0 -0
  239. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.printdata.rst +0 -0
  240. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.printgreen.rst +0 -0
  241. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.printmagenta.rst +0 -0
  242. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.printmean.rst +0 -0
  243. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.printmedian.rst +0 -0
  244. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.printred.rst +0 -0
  245. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.printtologfile.rst +0 -0
  246. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.printv.rst +0 -0
  247. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.printvars.rst +0 -0
  248. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.printyellow.rst +0 -0
  249. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.progressbar.rst +0 -0
  250. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.progressbars.rst +0 -0
  251. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.quickobj.rst +0 -0
  252. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.rst +0 -0
  253. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.sigfig.rst +0 -0
  254. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.sigfiground.rst +0 -0
  255. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.sigfigs.rst +0 -0
  256. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_printing.slacknotification.rst +0 -0
  257. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_profiling.LimitExceeded.rst +0 -0
  258. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_profiling.benchmark.rst +0 -0
  259. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_profiling.checkmem.rst +0 -0
  260. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_profiling.checkram.rst +0 -0
  261. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_profiling.cprofile.rst +0 -0
  262. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_profiling.listfuncs.rst +0 -0
  263. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_profiling.mprofile.rst +0 -0
  264. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_profiling.profile.rst +0 -0
  265. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_profiling.resourcemonitor.rst +0 -0
  266. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_profiling.rst +0 -0
  267. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_profiling.tracecalls.rst +0 -0
  268. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_settings.ScirisOptions.rst +0 -0
  269. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_settings.help.rst +0 -0
  270. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_settings.parse_env.rst +0 -0
  271. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_settings.rst +0 -0
  272. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.KeyNotFoundError.rst +0 -0
  273. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.LazyModule.rst +0 -0
  274. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.Link.rst +0 -0
  275. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.LinkException.rst +0 -0
  276. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.asciify.rst +0 -0
  277. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.autolist.rst +0 -0
  278. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.checktype.rst +0 -0
  279. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.cp.rst +0 -0
  280. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.dcp.rst +0 -0
  281. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.download.rst +0 -0
  282. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.fast_uuid.rst +0 -0
  283. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.flexstr.rst +0 -0
  284. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.getplatform.rst +0 -0
  285. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.getuser.rst +0 -0
  286. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.htmlify.rst +0 -0
  287. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.ifelse.rst +0 -0
  288. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.importbyname.rst +0 -0
  289. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.importbypath.rst +0 -0
  290. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.isarray.rst +0 -0
  291. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.isfunc.rst +0 -0
  292. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.isiterable.rst +0 -0
  293. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.isjupyter.rst +0 -0
  294. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.islinux.rst +0 -0
  295. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.ismac.rst +0 -0
  296. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.ismodule.rst +0 -0
  297. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.isnumber.rst +0 -0
  298. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.isstring.rst +0 -0
  299. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.iswindows.rst +0 -0
  300. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.mergedicts.rst +0 -0
  301. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.mergelists.rst +0 -0
  302. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.newlinejoin.rst +0 -0
  303. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.pp.rst +0 -0
  304. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.promotetoarray.rst +0 -0
  305. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.promotetolist.rst +0 -0
  306. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.robust_dcp.rst +0 -0
  307. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.rst +0 -0
  308. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.runcommand.rst +0 -0
  309. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.sanitizestr.rst +0 -0
  310. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.sha.rst +0 -0
  311. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.strjoin.rst +0 -0
  312. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.strsplit.rst +0 -0
  313. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.suggest.rst +0 -0
  314. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.swapdict.rst +0 -0
  315. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.toarray.rst +0 -0
  316. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.tolist.rst +0 -0
  317. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.traceback.rst +0 -0
  318. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.transposelist.rst +0 -0
  319. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.tryexcept.rst +0 -0
  320. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.uniquename.rst +0 -0
  321. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.urlopen.rst +0 -0
  322. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.uuid.rst +0 -0
  323. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_utils.wget.rst +0 -0
  324. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_version.rst +0 -0
  325. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_versioning.compareversions.rst +0 -0
  326. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_versioning.freeze.rst +0 -0
  327. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_versioning.getcaller.rst +0 -0
  328. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_versioning.gitinfo.rst +0 -0
  329. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_versioning.loadarchive.rst +0 -0
  330. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_versioning.loadmetadata.rst +0 -0
  331. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_versioning.metadata.rst +0 -0
  332. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_versioning.require.rst +0 -0
  333. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_versioning.rst +0 -0
  334. {sciris-3.2.6 → sciris-3.2.8}/docs/api/_autosummary/sciris.sc_versioning.savearchive.rst +0 -0
  335. {sciris-3.2.6 → sciris-3.2.8}/docs/api/all.rst +0 -0
  336. {sciris-3.2.6 → sciris-3.2.8}/docs/api/containers.rst +0 -0
  337. {sciris-3.2.6 → sciris-3.2.8}/docs/api/files.rst +0 -0
  338. {sciris-3.2.6 → sciris-3.2.8}/docs/api/index.rst +0 -0
  339. {sciris-3.2.6 → sciris-3.2.8}/docs/api/math.rst +0 -0
  340. {sciris-3.2.6 → sciris-3.2.8}/docs/api/parallel.rst +0 -0
  341. {sciris-3.2.6 → sciris-3.2.8}/docs/api/printing.rst +0 -0
  342. {sciris-3.2.6 → sciris-3.2.8}/docs/api/utils.rst +0 -0
  343. {sciris-3.2.6 → sciris-3.2.8}/docs/build_docs +0 -0
  344. {sciris-3.2.6 → sciris-3.2.8}/docs/conf.py +0 -0
  345. {sciris-3.2.6 → sciris-3.2.8}/docs/contributing.rst +0 -0
  346. {sciris-3.2.6 → sciris-3.2.8}/docs/favicon.ico +0 -0
  347. {sciris-3.2.6 → sciris-3.2.8}/docs/freeze_env +0 -0
  348. {sciris-3.2.6 → sciris-3.2.8}/docs/index.rst +0 -0
  349. {sciris-3.2.6 → sciris-3.2.8}/docs/overview.rst +0 -0
  350. {sciris-3.2.6 → sciris-3.2.8}/docs/requirements.txt +0 -0
  351. {sciris-3.2.6 → sciris-3.2.8}/docs/sciris-citation.bib +0 -0
  352. {sciris-3.2.6 → sciris-3.2.8}/docs/sciris-logo-grey-small.png +0 -0
  353. {sciris-3.2.6 → sciris-3.2.8}/docs/sciris-logo-grey.png +0 -0
  354. {sciris-3.2.6 → sciris-3.2.8}/docs/sciris-logo-white-small.png +0 -0
  355. {sciris-3.2.6 → sciris-3.2.8}/docs/sciris-logo.png +0 -0
  356. {sciris-3.2.6 → sciris-3.2.8}/docs/sciris-showcase-code.png +0 -0
  357. {sciris-3.2.6 → sciris-3.2.8}/docs/sciris-showcase-output.png +0 -0
  358. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/README.md +0 -0
  359. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/clean_outputs +0 -0
  360. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/dancing_lines.gif +0 -0
  361. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/img-advanced.gif +0 -0
  362. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/img-arrays.png +0 -0
  363. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/img-dates.png +0 -0
  364. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/img-dicts.png +0 -0
  365. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/img-files.png +0 -0
  366. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/img-intro.png +0 -0
  367. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/img-parallel.png +0 -0
  368. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/img-plotting.png +0 -0
  369. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/img-printing.png +0 -0
  370. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/img-utils.png +0 -0
  371. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/index.rst +0 -0
  372. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/run_tutorials +0 -0
  373. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/sim1/sim.py +0 -0
  374. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/sim2/sim.py +0 -0
  375. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/tut_advanced.ipynb +0 -0
  376. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/tut_arrays.ipynb +0 -0
  377. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/tut_dates.ipynb +0 -0
  378. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/tut_dicts.ipynb +0 -0
  379. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/tut_files.ipynb +0 -0
  380. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/tut_intro.ipynb +0 -0
  381. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/tut_parallel.ipynb +0 -0
  382. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/tut_plotting.ipynb +0 -0
  383. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/tut_printing.ipynb +0 -0
  384. {sciris-3.2.6 → sciris-3.2.8}/docs/tutorials/tut_utils.ipynb +0 -0
  385. {sciris-3.2.6 → sciris-3.2.8}/docs/whatsnew.rst +0 -0
  386. {sciris-3.2.6 → sciris-3.2.8}/pyproject.toml +0 -0
  387. {sciris-3.2.6 → sciris-3.2.8}/sciris/README.md +0 -0
  388. {sciris-3.2.6 → sciris-3.2.8}/sciris/__init__.py +0 -0
  389. {sciris-3.2.6 → sciris-3.2.8}/sciris/_extras/README.md +0 -0
  390. {sciris-3.2.6 → sciris-3.2.8}/sciris/_extras/__init__.py +0 -0
  391. {sciris-3.2.6 → sciris-3.2.8}/sciris/_extras/ansicolors.py +0 -0
  392. {sciris-3.2.6 → sciris-3.2.8}/sciris/_extras/legacy.py +0 -0
  393. {sciris-3.2.6 → sciris-3.2.8}/sciris/fancy.mplstyle +0 -0
  394. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_colors.py +0 -0
  395. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_dataframe.py +0 -0
  396. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_datetime.py +0 -0
  397. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_fileio.py +0 -0
  398. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_math.py +0 -0
  399. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_nested.py +0 -0
  400. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_parallel.py +0 -0
  401. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_plotting.py +0 -0
  402. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_printing.py +0 -0
  403. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_settings.py +0 -0
  404. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_utils.py +0 -0
  405. {sciris-3.2.6 → sciris-3.2.8}/sciris/sc_versioning.py +0 -0
  406. {sciris-3.2.6 → sciris-3.2.8}/sciris/simple.mplstyle +0 -0
  407. {sciris-3.2.6 → sciris-3.2.8}/sciris.egg-info/dependency_links.txt +0 -0
  408. {sciris-3.2.6 → sciris-3.2.8}/sciris.egg-info/requires.txt +0 -0
  409. {sciris-3.2.6 → sciris-3.2.8}/sciris.egg-info/top_level.txt +0 -0
  410. {sciris-3.2.6 → sciris-3.2.8}/setup.cfg +0 -0
  411. {sciris-3.2.6 → sciris-3.2.8}/tests/.coveragerc +0 -0
  412. {sciris-3.2.6 → sciris-3.2.8}/tests/README.rst +0 -0
  413. {sciris-3.2.6 → sciris-3.2.8}/tests/check_coverage +0 -0
  414. {sciris-3.2.6 → sciris-3.2.8}/tests/check_style +0 -0
  415. {sciris-3.2.6 → sciris-3.2.8}/tests/files/archive_2023-04-19.zip +0 -0
  416. {sciris-3.2.6 → sciris-3.2.8}/tests/files/deadclass.obj +0 -0
  417. {sciris-3.2.6 → sciris-3.2.8}/tests/files/deadclass.py +0 -0
  418. {sciris-3.2.6 → sciris-3.2.8}/tests/files/exampledata.xlsx +0 -0
  419. {sciris-3.2.6 → sciris-3.2.8}/tests/files/examplefont.ttf +0 -0
  420. {sciris-3.2.6 → sciris-3.2.8}/tests/files/make_archive.py +0 -0
  421. {sciris-3.2.6 → sciris-3.2.8}/tests/files/make_deadclass.py +0 -0
  422. {sciris-3.2.6 → sciris-3.2.8}/tests/files/pickle_2021-01-01.obj +0 -0
  423. {sciris-3.2.6 → sciris-3.2.8}/tests/files/pickle_2022-01-01.obj +0 -0
  424. {sciris-3.2.6 → sciris-3.2.8}/tests/pylint_report.txt +0 -0
  425. {sciris-3.2.6 → sciris-3.2.8}/tests/pytest.ini +0 -0
  426. {sciris-3.2.6 → sciris-3.2.8}/tests/regression/README.rst +0 -0
  427. {sciris-3.2.6 → sciris-3.2.8}/tests/regression/run_downstream +0 -0
  428. {sciris-3.2.6 → sciris-3.2.8}/tests/regression/run_regression +0 -0
  429. {sciris-3.2.6 → sciris-3.2.8}/tests/regression/sciris2021-01-01.yml +0 -0
  430. {sciris-3.2.6 → sciris-3.2.8}/tests/regression/sciris2022-01-01.yml +0 -0
  431. {sciris-3.2.6 → sciris-3.2.8}/tests/regression/sciris2023-01-01.yml +0 -0
  432. {sciris-3.2.6 → sciris-3.2.8}/tests/regression/setup_envs +0 -0
  433. {sciris-3.2.6 → sciris-3.2.8}/tests/requirements.txt +0 -0
  434. {sciris-3.2.6 → sciris-3.2.8}/tests/run_tests +0 -0
  435. {sciris-3.2.6 → sciris-3.2.8}/tests/sc_test_utils.py +0 -0
  436. {sciris-3.2.6 → sciris-3.2.8}/tests/showcase_sciris.py +0 -0
  437. {sciris-3.2.6 → sciris-3.2.8}/tests/showcase_vanilla.py +0 -0
  438. {sciris-3.2.6 → sciris-3.2.8}/tests/test_asd.py +0 -0
  439. {sciris-3.2.6 → sciris-3.2.8}/tests/test_both_parallelizers.py +0 -0
  440. {sciris-3.2.6 → sciris-3.2.8}/tests/test_colors.py +0 -0
  441. {sciris-3.2.6 → sciris-3.2.8}/tests/test_dataframe.py +0 -0
  442. {sciris-3.2.6 → sciris-3.2.8}/tests/test_datetime.py +0 -0
  443. {sciris-3.2.6 → sciris-3.2.8}/tests/test_fileio.py +0 -0
  444. {sciris-3.2.6 → sciris-3.2.8}/tests/test_math.py +0 -0
  445. {sciris-3.2.6 → sciris-3.2.8}/tests/test_mp_objdict.py +0 -0
  446. {sciris-3.2.6 → sciris-3.2.8}/tests/test_nested.py +0 -0
  447. {sciris-3.2.6 → sciris-3.2.8}/tests/test_objdict_pickle_detailed.py +0 -0
  448. {sciris-3.2.6 → sciris-3.2.8}/tests/test_parallel.py +0 -0
  449. {sciris-3.2.6 → sciris-3.2.8}/tests/test_parallel_mp.py +0 -0
  450. {sciris-3.2.6 → sciris-3.2.8}/tests/test_parallel_odict.py +0 -0
  451. {sciris-3.2.6 → sciris-3.2.8}/tests/test_pickle_objdict.py +0 -0
  452. {sciris-3.2.6 → sciris-3.2.8}/tests/test_plotting.py +0 -0
  453. {sciris-3.2.6 → sciris-3.2.8}/tests/test_printing.py +0 -0
  454. {sciris-3.2.6 → sciris-3.2.8}/tests/test_profiling.py +0 -0
  455. {sciris-3.2.6 → sciris-3.2.8}/tests/test_settings.py +0 -0
  456. {sciris-3.2.6 → sciris-3.2.8}/tests/test_utils.py +0 -0
  457. {sciris-3.2.6 → sciris-3.2.8}/tests/test_versioning.py +0 -0
@@ -2,7 +2,7 @@ name: Sciris cron tests
2
2
  on:
3
3
  workflow_dispatch:
4
4
  schedule:
5
- - cron: "0 0 * * 0" # Run every Sunday at midnight
5
+ - cron: "0 0 * * *" # Run every day at midnight
6
6
 
7
7
  jobs:
8
8
  ci-tests:
@@ -7,6 +7,15 @@ All major updates to Sciris are documented here.
7
7
 
8
8
  By import convention, components of the Sciris library are listed beginning with ``sc.``, e.g. ``sc.odict()``.
9
9
 
10
+ Version 3.2.8 (2026-02-28)
11
+ --------------------------
12
+ #. Changed resolution order in :class:`sc.objdict() <sc_odict.objdict>` so that dunder attributes (e.g. ``__await__``) are never accidentally set as dict keys. Attempting to set an existing attribute as a key now raises ``KeyError`` instead of ``ValueError``.
13
+ #. Fixed a bug in :class:`sc.profile() <sc_profiling.profile>` that prevented profiling information from being printed for certain combinations of filenames.
14
+
15
+ Version 3.2.7 (2026-02-18)
16
+ --------------------------
17
+ #. Refactored :class:`sc.asd() <sc_asd.asd>` to be more robust to different parameter inputs and different objective function return values.
18
+
10
19
  Version 3.2.6 (2026-02-12)
11
20
  --------------------------
12
21
  #. Added :class:`sc.argparse() <sc_odict.argparse>`, a simple argument parser based on ``sc.objdict``.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sciris
3
- Version: 3.2.6
3
+ Version: 3.2.8
4
4
  Summary: Fast, flexible tools to simplify scientific Python
5
5
  Author-email: Sciris Development Team <info@sciris.org>
6
6
  License-Expression: MIT
@@ -0,0 +1,4 @@
1
+ {
2
+ "url": "https://context7.com/sciris/sciris",
3
+ "public_key": "pk_RAjZiMtFTxRqXHnY6XFE3"
4
+ }
@@ -9,23 +9,55 @@ This algorithm is published as:
9
9
  """
10
10
 
11
11
  import time
12
+ import warnings
12
13
  import numpy as np
13
14
  import sciris as sc
14
15
 
15
16
  __all__ = ['asd']
16
17
 
17
18
 
19
+ def _consistent_shape(userinput, origshape=False):
20
+ """ Ensure inputs have the right shape and data type. """
21
+ output = np.reshape(np.array(userinput, dtype='float'), -1)
22
+ if origshape:
23
+ return output, np.shape(userinput)
24
+ return output
25
+
26
+
27
+ def _improvement_ratio(fval_old, fval_new, eps=1e-12):
28
+ """ Compute improvement ratio with divide-by-zero guard
29
+
30
+ Returns fval_old/fval_new, or 1 when both near zero, or a large value when only fval_new is near zero.
31
+ """
32
+ if abs(fval_new) < eps and abs(fval_old) < eps:
33
+ return 1.0
34
+ if abs(fval_new) < eps:
35
+ return 1.0 / eps
36
+ return fval_old / float(fval_new)
37
+
38
+
39
+ def _validate_fval(fval, die=True):
40
+ """ Validate that the objective function returns a scalar """
41
+ if not sc.isnumber(fval):
42
+ if isinstance(fval, np.ndarray) and fval.size == 1: # Automatically convert size-1 arrays to scalars
43
+ fval = fval[0]
44
+ else:
45
+ errormsg = f'ASD: The objective function should return a scalar, not: {fval} (type: {type(fval)})'
46
+ raise ValueError(errormsg)
47
+ return fval
48
+
49
+
18
50
  def asd(function, x, args=None, stepsize=0.1, sinc=2, sdec=2, pinc=2, pdec=2,
19
51
  pinitial=None, sinitial=None, xmin=None, xmax=None, maxiters=None, maxtime=None,
20
52
  abstol=1e-6, reltol=1e-3, stalliters=None, stoppingfunc=None, randseed=None,
21
- label=None, verbose=1, minval=0, **kwargs):
53
+ label=None, verbose=1, minval=0, die=True, **kwargs):
22
54
  """
23
55
  Optimization using adaptive stochastic descent (ASD). Can be used as a faster
24
56
  and more powerful alternative to e.g. :func:`scipy.optimize.minimize()`.
25
57
 
26
- ASD starts at ``x0`` and attempts to find a local minimizer ``x`` of the function ``func()``.
27
- ``func()`` accepts input ``x`` and returns a scalar function value evaluated at ``x``.
28
- ``x0`` can be a scalar, list, or Numpy array of any size.
58
+ ASD starts at ``x`` and attempts to find a local minimizer of the function ``function()``.
59
+ ``function()`` accepts input ``x`` and returns a scalar function value evaluated at ``x``.
60
+ ``x`` can be a scalar, list, or Numpy array of any size.
29
61
 
30
62
  Args:
31
63
  function (func): The function to minimize
@@ -51,6 +83,7 @@ def asd(function, x, args=None, stepsize=0.1, sinc=2, sdec=2, pinc=2, pdec=2,
51
83
  label (None): A label to use to annotate the output
52
84
  verbose (1): How much information to print during the run (max 3); less than one will print out once every 1/verbose steps
53
85
  minval (0): Minimum value the objective function can take
86
+ die (True): If True, raise when the objective function raises; if False, treat that trial as np.inf and continue
54
87
 
55
88
  Returns:
56
89
  objdict (see below)
@@ -78,13 +111,13 @@ def asd(function, x, args=None, stepsize=0.1, sinc=2, sdec=2, pinc=2, pdec=2,
78
111
  result = sc.asd(np.linalg.norm, [1, 2, 3])
79
112
  print(result.x)
80
113
 
81
- # With arguments
82
- def my_func(x, scale=1.0, weight=1.0): # Example function with keywords
114
+ # With arguments: positional via args, or dict of keywords, or keyword arguments
115
+ def my_func(x, scale=1.0, weight=1.0): # Example function with keywords
83
116
  return abs((x[0] - 1)) + abs(x[1] + 2)*scale + abs(x[2] + 3)*weight
84
117
 
85
118
  result = sc.asd(my_func, x=[0, 0, 1], args=[0.5, 0.1]) # Option 1 for passing arguments
86
- result = sc.asd(my_func, x=[0, 0, 1], args=dict(scale=0.5, weight=0.1)) # Option 1 for passing arguments
87
- result = sc.asd(my_func, x=[0, 0, 1], scale=0.5, weight=0.1) # Option 2 for passing arguments
119
+ result = sc.asd(my_func, x=[0, 0, 1], args=dict(scale=0.5, weight=0.1)) # Option 2 for passing arguments
120
+ result = sc.asd(my_func, x=[0, 0, 1], scale=0.5, weight=0.1) # Option 3 for passing arguments
88
121
 
89
122
  Please use the following citation for this method:
90
123
 
@@ -97,82 +130,104 @@ def asd(function, x, args=None, stepsize=0.1, sinc=2, sdec=2, pinc=2, pdec=2,
97
130
  rng = np.random.default_rng(randseed)
98
131
  if verbose >= 2: print(f'ASD: Launching with random seed {randseed}')
99
132
 
100
- def consistentshape(userinput, origshape=False):
101
- """
102
- Make sure inputs have the right shape and data type.
103
- """
104
- output = np.reshape(np.array(userinput, dtype='float'), -1)
105
- if origshape: return output, np.shape(userinput)
106
- else: return output
107
-
108
- # Handle inputs and set defaults
109
- if maxtime is None: maxtime = 3600
110
- if maxiters is None: maxiters = 1000
111
- maxrangeiters = 100 # Number of times to try generating a new parameter
112
- x, origshape = consistentshape(x, origshape=True) # Turn it into a vector but keep the original shape (not necessarily class, though)
113
- nparams = len(x) # Number of parameters
114
- if not nparams: # pragma: no cover
133
+ # Reshape initial point and get parameter count
134
+ x, origshape = _consistent_shape(x, origshape=True)
135
+ nparams = len(x)
136
+ maxrangeiters = 100 # Number of times to try generating a new parameter
137
+
138
+ # Set defaults in one place
139
+ if maxtime is None:
140
+ maxtime = 3600
141
+ if maxiters is None:
142
+ maxiters = 1000
143
+ if label is None:
144
+ label = ''
145
+ if stalliters is None:
146
+ stalliters = 10 * nparams
147
+ stalliters = int(stalliters)
148
+ maxiters = int(maxiters)
149
+ eps = 1e-12
150
+
151
+ # Validate input vector length
152
+ if not nparams:
115
153
  errormsg = 'ASD: The length of the input vector cannot be zero'
116
154
  raise ValueError(errormsg)
117
- if sinc<1: # pragma: no cover
118
- print('ASD: sinc cannot be less than 1; resetting to 2')
155
+
156
+ # Validate learning rates (must be >= 1)
157
+ if sinc < 1:
158
+ errormsg = 'ASD: sinc cannot be less than 1; resetting to 2'
159
+ if die:
160
+ raise ValueError(errormsg)
161
+ warnings.warn(errormsg)
119
162
  sinc = 2
120
- if sdec<1: # pragma: no cover
121
- print('ASD: sdec cannot be less than 1; resetting to 2')
163
+ if sdec < 1:
164
+ errormsg = 'ASD: sdec cannot be less than 1; resetting to 2'
165
+ if die:
166
+ raise ValueError(errormsg)
167
+ warnings.warn(errormsg)
122
168
  sdec = 2
123
- if pinc<1: # pragma: no cover
124
- print('ASD: pinc cannot be less than 1; resetting to 2')
169
+ if pinc < 1:
170
+ errormsg = 'ASD: pinc cannot be less than 1; resetting to 2'
171
+ if die:
172
+ raise ValueError(errormsg)
173
+ warnings.warn(errormsg)
125
174
  pinc = 2
126
- if pdec<1: # pragma: no cover
127
- print('ASD: pdec cannot be less than 1; resetting to 2')
175
+ if pdec < 1:
176
+ errormsg = 'ASD: pdec cannot be less than 1; resetting to 2'
177
+ if die:
178
+ raise ValueError(errormsg)
179
+ warnings.warn(errormsg)
128
180
  pdec = 2
129
181
 
130
- # Set initial parameter selection probabilities -- uniform by default
131
- if pinitial is None: probabilities = np.ones(2 * nparams)
132
- else: probabilities = consistentshape(pinitial)
133
- if not sum(probabilities): # pragma: no cover
182
+ # Set initial parameter selection probabilities (uniform by default)
183
+ if pinitial is None:
184
+ probabilities = np.ones(2 * nparams)
185
+ else:
186
+ probabilities = _consistent_shape(pinitial)
187
+ if not sum(probabilities):
134
188
  errormsg = 'ASD: The sum of input probabilities cannot be zero'
135
189
  raise ValueError(errormsg)
136
190
 
137
- # Handle step sizes
191
+ # Step sizes
138
192
  if sinitial is None:
139
193
  stepsizes = abs(stepsize * x)
140
- stepsizes = np.concatenate((stepsizes, stepsizes)) # need to duplicate since two for each parameter
194
+ stepsizes = np.concatenate((stepsizes, stepsizes)) # Two entries per parameter (up/down)
141
195
  else:
142
- stepsizes = consistentshape(sinitial)
196
+ stepsizes = _consistent_shape(sinitial)
143
197
 
144
- # Handle x limits
145
- xmin = np.zeros(nparams) - np.inf if xmin is None else consistentshape(xmin)
146
- xmax = np.zeros(nparams) + np.inf if xmax is None else consistentshape(xmax)
198
+ # Parameter bounds
199
+ xmin = np.zeros(nparams) - np.inf if xmin is None else _consistent_shape(xmin)
200
+ xmax = np.zeros(nparams) + np.inf if xmax is None else _consistent_shape(xmax)
147
201
 
148
- # Final input checking
149
- if sum(np.isnan(x)): # pragma: no cover
202
+ # Reject NaN in starting point
203
+ if sum(np.isnan(x)):
150
204
  errormsg = f'ASD: At least one value in the vector of starting points is NaN:\n{x}'
151
205
  raise ValueError(errormsg)
152
- if label is None: label = ''
153
- if stalliters is None: stalliters = 10 * nparams # By default, try 10 times per parameter on average
154
- stalliters = int(stalliters)
155
- maxiters = int(maxiters)
156
206
 
157
207
  # Initialization
158
- if all(stepsizes == 0): stepsizes += stepsize # Handle the case where all step sizes are 0
159
- if any(stepsizes == 0): stepsizes[stepsizes == 0] = np.mean(stepsizes[stepsizes != 0]) # Replace step sizes of zeros with the mean of non-zero entries
160
- if args is None: # Reset if no function arguments supplied
208
+ if all(stepsizes == 0):
209
+ stepsizes += stepsize
210
+ if any(stepsizes == 0):
211
+ stepsizes[stepsizes == 0] = np.mean(stepsizes[stepsizes != 0])
212
+ if args is None:
161
213
  args = []
162
- elif isinstance(args, dict): # It's actually kwargs supplied
214
+ elif isinstance(args, dict):
163
215
  kwargs = sc.mergedicts(args, kwargs)
164
216
  args = []
165
- fval = function(x, *args, **kwargs) # Calculate initial value of the objective function
166
- fvalorig = fval # Store the original value of the objective function, since fval is overwritten on each step
167
- xorig = x.copy() # Keep the original x, just in case
168
-
169
- # Initialize history
170
- abserrorhistory = np.zeros(stalliters) # Store previous error changes
171
- relerrorhistory = np.zeros(stalliters) # Store previous error changes
172
- fvals = np.zeros(maxiters + 1) # Store all objective function values
173
- allsteps = np.zeros((maxiters + 1, nparams)) # Store all parameters
174
- fvals[0] = fvalorig # Store initial function output
175
- allsteps[0, :] = xorig # Store initial input vector
217
+
218
+ # Get initial function value
219
+ fval = function(x, *args, **kwargs)
220
+ fval = _validate_fval(fval, die=die)
221
+ fvalorig = fval
222
+ xorig = x.copy()
223
+
224
+ # Allocate history arrays
225
+ abserrorhistory = np.zeros(stalliters)
226
+ relerrorhistory = np.zeros(stalliters)
227
+ fvals = np.zeros(maxiters + 1)
228
+ allsteps = np.zeros((maxiters + 1, nparams))
229
+ fvals[0] = fvalorig
230
+ allsteps[0, :] = xorig
176
231
 
177
232
  # Prepare for the loop
178
233
  count = 0 # Keep track of how many iterations have occurred
@@ -180,23 +235,23 @@ def asd(function, x, args=None, stepsize=0.1, sinc=2, sdec=2, pinc=2, pdec=2,
180
235
  offset = ' ' * 4 # Offset the print statements
181
236
  exitreason = 'Unknown exit reason' # Catch everything else
182
237
 
183
- # Loop
238
+ # Main optimization loop
184
239
  while True:
185
240
 
186
- # Handle initialization cases
241
+ # Skip if already at minimum
187
242
  if fvalorig == minval:
188
243
  exitreason = f'Objective function already at minimum value ({fvalorig}), skipping optimization'
189
244
  break
190
- elif fvalorig < 0 and verbose:
245
+ if fvalorig < 0 and verbose:
191
246
  print(f'ASD: Warning, negative objective function starting value ({fvalorig:n}) could lead to unexpected behavior')
192
247
 
193
- # Begin the loop
194
- count += 1 # Increment the count
195
- if verbose >= 3: print(f'\n\n Count={count} \n x={x} \n probabilities={probabilities} \n stepsizes={stepsizes}')
248
+ count += 1
249
+ if verbose >= 3:
250
+ print(f'\n\n Count={count} \n x={x} \n probabilities={probabilities} \n stepsizes={stepsizes}')
196
251
 
197
- # Calculate next parameters
198
- probabilities = probabilities / sum(probabilities) # Normalize probabilities
199
- cumprobs = np.cumsum(probabilities) # Calculate the cumulative distribution
252
+ # Normalize probabilities and sample a parameter/direction
253
+ probabilities = probabilities / sum(probabilities)
254
+ cumprobs = np.cumsum(probabilities)
200
255
  inrange = False
201
256
  for r in range(maxrangeiters): # Try to find parameters within range
202
257
  choice = np.flatnonzero(cumprobs > rng.random())[0] # Choose a parameter and upper/lower at random
@@ -206,93 +261,95 @@ def asd(function, x, args=None, stepsize=0.1, sinc=2, sdec=2, pinc=2, pdec=2,
206
261
  if newval<xmin[par]: newval = xmin[par] # Reset to the lower limit
207
262
  if newval>xmax[par]: newval = xmax[par] # Reset to the upper limit
208
263
  inrange = (newval != x[par])
209
- if verbose >= 3: print(offset*2 + f'count={count} r={r}, choice={choice}, par={par}, x[par]={x[par]}, pm={(-1)**pm}, step={stepsizes[choice]}, newval={newval}, xmin={xmin[par]}, xmax={xmax[par]}, inrange={inrange}')
210
- if inrange: # Proceed as long as they're not equal
264
+ if verbose >= 3:
265
+ print(offset*2 + f'count={count} r={r}, choice={choice}, par={par}, x[par]={x[par]}, pm={(-1)**pm}, step={stepsizes[choice]}, newval={newval}, xmin={xmin[par]}, xmax={xmax[par]}, inrange={inrange}')
266
+ if inrange:
211
267
  break
212
268
  if not inrange: # Treat it as a failure if a value in range can't be found
213
269
  probabilities[choice] = probabilities[choice] / pdec
214
270
  stepsizes[choice] = stepsizes[choice] / sdec
215
271
 
216
- # Calculate the new value
217
- xnew = x.copy() # Initialize the new parameter set
218
- xnew[par] = newval # Update the new parameter set
219
- fvalnew = function(xnew, *args, **kwargs) # Calculate the objective function for the new parameter set
220
- eps = 1e-12 # Small value to avoid divide-by-zero errors
221
- if abs(fvalnew)<eps and abs(fval)<eps: ratio = 1 # They're both zero: set the ratio to 1
222
- elif abs(fvalnew)<eps: ratio = 1.0/eps # Only the denominator is zero: reset to the maximum ratio
223
- else: ratio = fval/float(fvalnew) # The normal situation: calculate the real ratio
224
- abserrorhistory[np.mod(count, stalliters)] = max(0, fval-fvalnew) # Keep track of improvements in the error
225
- relerrorhistory[np.mod(count, stalliters)] = max(0, ratio-1.0) # Keep track of improvements in the error
226
- if verbose >= 2: print(offset + f'step={count} choice={choice}, par={par}, pm={pm}, origval={x[par]}, newval={xnew[par]}')
272
+ # Evaluate objective at proposed point
273
+ xnew = x.copy()
274
+ xnew[par] = newval
275
+ try:
276
+ fvalnew = function(xnew, *args, **kwargs)
277
+ fvalnew = _validate_fval(fvalnew, die=die)
278
+ except Exception as e:
279
+ if die:
280
+ raise
281
+ warnings.warn(f'ASD: Objective function raised on step {count}; treating trial as np.inf. Error: {e}')
282
+ fvalnew = np.inf
283
+ ratio = _improvement_ratio(fval, fvalnew, eps)
284
+
285
+ # Update improvement history
286
+ abserrorhistory[count % stalliters] = max(0, fval - fvalnew)
287
+ relerrorhistory[count % stalliters] = max(0, ratio - 1.0)
288
+ if verbose >= 2:
289
+ print(offset + f'step={count} choice={choice}, par={par}, pm={pm}, origval={x[par]}, newval={xnew[par]}')
227
290
  if newval < 0 and verbose:
228
291
  print(f'ASD: Warning, negative objective function ({newval:n}) on step {count} could lead to unexpected behavior')
229
292
 
230
- # Check if this step was an improvement
231
- fvalold = fval # Store old fval
232
- if fvalnew < fvalold: # New parameter set is better than previous one
233
- probabilities[choice] = probabilities[choice] * pinc # Increase probability of picking this parameter again
234
- stepsizes[choice] = stepsizes[choice] * sinc # Increase size of step for next time
235
- x = xnew # Reset current parameters
236
- fval = fvalnew # Reset current error
237
- flag = '++' # Marks an improvement
238
- else: # New parameter set is the same or worse than the previous one
239
- probabilities[choice] = probabilities[choice] / pdec # Decrease probability of picking this parameter again
240
- stepsizes[choice] = stepsizes[choice] / sdec # Decrease size of step for next time
241
- flag = '--' # Marks no change
242
- if np.isnan(fvalnew):
243
- if verbose >= 1: print('ASD: Warning, objective function returned NaN')
244
- if verbose > 0 and not (count % max(1, int(1.0/verbose))): # Print out every 1/verbose steps
245
- orig, best, new, diff = sc.sigfig([fvalorig, fvalold, fvalnew, fvalnew-fvalold])
293
+ # Accept or reject step and update learning state
294
+ fvalold = fval
295
+ if fvalnew < fvalold:
296
+ probabilities[choice] = probabilities[choice] * pinc
297
+ stepsizes[choice] = stepsizes[choice] * sinc
298
+ x = xnew
299
+ fval = fvalnew
300
+ flag = '++'
301
+ else:
302
+ probabilities[choice] = probabilities[choice] / pdec
303
+ stepsizes[choice] = stepsizes[choice] / sdec
304
+ flag = '--'
305
+ if np.isnan(fvalnew) and verbose >= 1:
306
+ print('ASD: Warning, objective function returned NaN')
307
+ if verbose > 0 and not (count % max(1, int(1.0/verbose))):
308
+ orig, best, new, diff = sc.sigfig([fvalorig, fvalold, fvalnew, fvalnew - fvalold])
246
309
  print(offset + label + f' step {count} ({time.time()-start:0.1f} s) {flag} (orig:{orig} | best:{best} | new:{new} | diff:{diff})')
247
310
 
248
- # Store output information
249
- fvals[count] = fval # Store objective function evaluations
250
- allsteps[count, :] = x # Store parameters
311
+ # Record history for this iteration
312
+ fvals[count] = fval
313
+ allsteps[count, :] = x
251
314
 
252
315
  # Stopping criteria
253
316
  if count >= maxiters: # Stop if the iteration limit is exceeded # pragma: no cover
254
317
  exitreason = 'Maximum iterations reached'
255
318
  break
256
- if (time.time() - start) > maxtime: # pragma: no cover
319
+ if (time.time() - start) > maxtime: # Stop if the time limit is exceeded # pragma: no cover
257
320
  strtime, strmax = sc.sigfig([(time.time()-start), maxtime])
258
321
  exitreason = f'Time limit reached ({strtime} > {strmax})'
259
322
  break
260
- if (count > stalliters) and (abs(np.mean(abserrorhistory)) < abstol): # Stop if improvement is too small
323
+ if (count > stalliters) and (abs(np.mean(abserrorhistory)) < abstol): # Stop if absolute improvement is too small
261
324
  strabs, strtol = sc.sigfig([np.mean(abserrorhistory), abstol])
262
325
  exitreason = f'Absolute improvement too small ({strabs} < {strtol})'
263
326
  break
264
- if (count > stalliters) and (sum(relerrorhistory) < reltol): # Stop if improvement is too small
327
+ if (count > stalliters) and (sum(relerrorhistory) < reltol): # Stop if relativeimprovement is too small
265
328
  strrel, strtol = sc.sigfig([np.mean(relerrorhistory), reltol])
266
329
  exitreason = f'Relative improvement too small ({strrel} < {strtol})'
267
330
  break
268
- if stoppingfunc and stoppingfunc(): # pragma: no cover
331
+ if stoppingfunc and stoppingfunc(): # Stop if explicitly requested # pragma: no cover
269
332
  exitreason = 'Stopping function called'
270
333
  break
271
- if fval == minval:
334
+ if fval == minval: # Stop if the objective function value is at the minimum
272
335
  exitreason = f'Minimum objective function value reached ({fval})'
273
336
  break
274
337
 
275
- # Return
338
+ # Build and return result
276
339
  if verbose > 0:
277
340
  orig, best = sc.sigfig([fvals[0], fvals[count]])
278
- eps = 1e-12 # Small value to avoid divide-by-zero errors
279
- if abs(fvals[count])<eps and abs(fvals[0])<eps:
280
- ratio = 1 # They're both zero: set the ratio to 1
281
- elif abs(fvals[0])<eps:
282
- ratio = 1.0/eps # Only the denominator is zero: reset to the maximum ratio
283
- else:
284
- ratio = fvals[count]/float(fvals[0]) # The normal situation: calculate the real ratio
285
-
341
+ ratio = _improvement_ratio(fvals[0], fvals[count], eps)
286
342
  print(f'=== {label} {exitreason} ({count} steps, orig: {orig} | best: {best} | ratio: {ratio}) ===')
287
343
 
288
- output = sc.objdict()
289
- output['x'] = np.reshape(x, origshape) # Parameters
290
- output['fval'] = fvals[count]
291
- output['exitreason'] = exitreason
292
- output['details'] = sc.objdict()
293
- output['details']['fvals'] = fvals[:count+1] # Function evaluations
294
- output['details']['xvals'] = allsteps[:count+1, :]
295
- output['details']['probabilities'] = probabilities
296
- output['details']['stepsizes'] = stepsizes
297
-
298
- return output # Return parameter vector as well as details about run
344
+ output = sc.objdict(
345
+ x = np.reshape(x, origshape), # Parameters
346
+ fval = fvals[count],
347
+ exitreason = exitreason,
348
+ details = sc.objdict(
349
+ fvals = fvals[:count+1], # Function evaluations
350
+ xvals = allsteps[:count+1, :],
351
+ probabilities = probabilities,
352
+ stepsizes = stepsizes
353
+ )
354
+ )
355
+ return output
@@ -5,11 +5,6 @@ Highlights:
5
5
  - :class:`sc.odict() <odict>`: flexible container representing the best-of-all-worlds across dicts, lists, and arrays
6
6
  - :class:`objdict`: like an odict, but allows get/set via e.g. ``foo.bar`` instead of ``foo['bar']``
7
7
  """
8
-
9
- ##############################################################################
10
- #%% odict class
11
- ##############################################################################
12
-
13
8
  import re
14
9
  import sys
15
10
  import json
@@ -67,6 +62,11 @@ class counter(co.Counter):
67
62
  raise AttributeError(errormsg) from e
68
63
 
69
64
 
65
+ ##############################################################################
66
+ #%% odict class
67
+ ##############################################################################
68
+
69
+
70
70
  class odict(dict):
71
71
  """
72
72
  Ordered dictionary with integer indexing
@@ -138,7 +138,7 @@ class odict(dict):
138
138
  if defaultdict != 'nested' and not callable(defaultdict): # pragma: no cover
139
139
  errormsg = f'The defaultdict argument must be either "nested" or callable, not {type(defaultdict)}'
140
140
  raise TypeError(errormsg)
141
- self._setattr('_defaultdict', defaultdict) # Use dict.__setattr__() since setattr() is overridden by sc.objdict()
141
+ self._setattr('_defaultdict', defaultdict) # Use object.__setattr__() since setattr() is overridden by sc.objdict()
142
142
 
143
143
  self._cache_keys()
144
144
  return
@@ -158,8 +158,8 @@ class odict(dict):
158
158
 
159
159
 
160
160
  def _setattr(self, key, value):
161
- """ Shortcut to dict method """
162
- return dict.__setattr__(self, key, value)
161
+ """ Shortcut to object method """
162
+ return object.__setattr__(self, key, value)
163
163
 
164
164
 
165
165
  def _setitem(self, key, value):
@@ -179,7 +179,7 @@ class odict(dict):
179
179
  if isinstance(key, sc._stringtypes) or isinstance(key, tuple): # Normal use case: just use a string key
180
180
  if isinstance(E, KeyError): # We already encountered an exception, usually a KeyError
181
181
  try: # Handle defaultdict behavior by first checking if it exists
182
- _defaultdict = dict.__getattribute__(self, '_defaultdict')
182
+ _defaultdict = object.__getattribute__(self, '_defaultdict')
183
183
  except:
184
184
  _defaultdict = None
185
185
  if _defaultdict is not None and allow_default: # If it does, use it, then get the key again
@@ -1208,8 +1208,8 @@ class objdict(odict):
1208
1208
  nested_parent = kwargs.pop('_nested_parent', None)
1209
1209
  nested_attr = kwargs.pop('_nested_attr', None)
1210
1210
  if nested_parent is not None:
1211
- odict.__setattr__(self, '_nested_parent', nested_parent)
1212
- odict.__setattr__(self, '_nested_attr', nested_attr)
1211
+ object.__setattr__(self, '_nested_parent', nested_parent)
1212
+ object.__setattr__(self, '_nested_attr', nested_attr)
1213
1213
  odict.__init__(self, *args, **kwargs) # Standard init
1214
1214
  return
1215
1215
 
@@ -1226,22 +1226,22 @@ class objdict(odict):
1226
1226
  return object.__getattribute__(self, attr)
1227
1227
  else:
1228
1228
  try: # First, try to get the attribute as an attribute
1229
- return odict.__getattribute__(self, attr)
1229
+ return object.__getattribute__(self, attr)
1230
1230
  except Exception as E: # If that fails, try to get it as a dict item, but pass along the original exception
1231
1231
  return self.__getitem__(attr, exception=E)
1232
1232
 
1233
1233
 
1234
1234
  def __setattr__(self, name, value):
1235
1235
  """ Set key in dict, not attribute! """
1236
- try:
1237
- odict.__getattribute__(self, name) # Try retrieving this as an attribute, expect AttributeError...
1238
- if name[:2] == '__': # If it starts with a double underscore, it's almost certainly an attribute, not a key
1239
- odict.__setattr__(self, name, value)
1240
- else:
1236
+ if name[:2] == '__': # If it starts with a double underscore, it's almost certainly an attribute, not a key
1237
+ return object.__setattr__(self, name, value)
1238
+ else:
1239
+ try:
1240
+ object.__getattribute__(self, name) # Try retrieving this as an attribute, expect AttributeError...
1241
1241
  errormsg = f'"{name}" exists as an attribute, so cannot be set as key; use setattribute() instead'
1242
- raise ValueError(errormsg)
1243
- except AttributeError:
1244
- return self.__setitem__(name, value) # If so, simply return
1242
+ raise KeyError(errormsg)
1243
+ except AttributeError:
1244
+ return self.__setitem__(name, value) # If so, simply return
1245
1245
 
1246
1246
 
1247
1247
  def __getitem__(self, attr, exception=None):
@@ -1250,7 +1250,7 @@ class objdict(odict):
1250
1250
  return odict.__getitem__(self, attr, allow_default=False) # Do not allow odict to handle default
1251
1251
  except Exception as E2: # If that fails, raise the original exception
1252
1252
  try: # Handle defaultdict behavior by first checking if it exists
1253
- _defaultdict = odict.__getattribute__(self, '_defaultdict')
1253
+ _defaultdict = object.__getattribute__(self, '_defaultdict')
1254
1254
  except:
1255
1255
  _defaultdict = None
1256
1256
  if _defaultdict is not None: # If it does, use it, then get the key again
@@ -1288,13 +1288,13 @@ class objdict(odict):
1288
1288
  try:
1289
1289
  del self[name]
1290
1290
  except: # pragma: no cover
1291
- odict.__delattr__(self, name)
1291
+ object.__delattr__(self, name)
1292
1292
  return
1293
1293
 
1294
1294
 
1295
1295
  def getattribute(self, name):
1296
1296
  """ Get attribute if truly desired """
1297
- return odict.__getattribute__(self, name)
1297
+ return object.__getattribute__(self, name)
1298
1298
 
1299
1299
 
1300
1300
  def setattribute(self, name, value, force=False):
@@ -1302,12 +1302,12 @@ class objdict(odict):
1302
1302
  if hasattr(self.__class__, name) and not force:
1303
1303
  errormsg = f'objdict attribute "{name}" is read-only'
1304
1304
  raise AttributeError(errormsg)
1305
- return odict.__setattr__(self, name, value)
1305
+ return object.__setattr__(self, name, value)
1306
1306
 
1307
1307
 
1308
1308
  def delattribute(self, name):
1309
1309
  """ Delete attribute if truly desired """
1310
- return odict.__delattr__(self, name)
1310
+ return object.__delattr__(self, name)
1311
1311
 
1312
1312
 
1313
1313
  class dictobj(dict):
@@ -580,7 +580,10 @@ class profile(sc.prettyobj):
580
580
  context_stack.pop()
581
581
 
582
582
  def visit_FunctionDef(self, node):
583
- if node.lineno == lineno:
583
+ # Check def line and decorator lines; in Python 3.11+,
584
+ # co_firstlineno points to the first decorator, not the def
585
+ match_lines = {node.lineno} | {d.lineno for d in node.decorator_list}
586
+ if lineno in match_lines:
584
587
  context_stack.append(node.name)
585
588
  nonlocal name
586
589
  name = '.'.join(context_stack)
@@ -656,8 +659,17 @@ class profile(sc.prettyobj):
656
659
  )
657
660
  self.output[name] = entry
658
661
 
659
- # The last name extracted is the name of the function that was run
660
- self.run_func_name = name
662
+ # Determine the name of the run function from the actual function object
663
+ # (can't assume the last chunk since line_profiler may sort by filename)
664
+ run_func = self.run_func
665
+ if hasattr(run_func, '__func__'):
666
+ run_func = run_func.__func__
667
+ if hasattr(run_func, '__code__'):
668
+ run_file = run_func.__code__.co_filename
669
+ run_lineno = run_func.__code__.co_firstlineno
670
+ self.run_func_name = self._path_to_name(run_file, run_lineno)
671
+ else:
672
+ self.run_func_name = name # Fallback to last chunk
661
673
 
662
674
  # Sort and convert to dataframe
663
675
  self.sort()
@@ -4,6 +4,6 @@ Version and license information.
4
4
 
5
5
  __all__ = ['__version__', '__versiondate__', '__license__']
6
6
 
7
- __version__ = '3.2.6'
8
- __versiondate__ = '2026-02-12'
7
+ __version__ = '3.2.8'
8
+ __versiondate__ = '2026-02-28'
9
9
  __license__ = f'Sciris {__version__} ({__versiondate__}) – © 2014-2026 by the Sciris Development Team'