uproot 5.7.3__tar.gz → 5.7.4__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 (342) hide show
  1. {uproot-5.7.3 → uproot-5.7.4}/.github/workflows/build-test.yml +13 -9
  2. {uproot-5.7.3 → uproot-5.7.4}/.github/workflows/upload-nightly-wheels.yml +1 -1
  3. {uproot-5.7.3 → uproot-5.7.4}/.pre-commit-config.yaml +2 -2
  4. {uproot-5.7.3 → uproot-5.7.4}/PKG-INFO +1 -1
  5. {uproot-5.7.3 → uproot-5.7.4}/docs-sphinx/basic.rst +16 -5
  6. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TProfile.py +62 -26
  7. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/reading.py +11 -6
  8. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/source/fsspec.py +26 -10
  9. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/version.py +2 -2
  10. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/writing/_cascade.py +37 -34
  11. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/writing/_dask_write.py +15 -12
  12. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/writing/identify.py +91 -20
  13. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/writing/writable.py +25 -18
  14. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1000-write-TProfiles.py +1 -1
  15. uproot-5.7.4/tests/test_1085_dask_write.py +89 -0
  16. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1393_TTree_virtual_arrays.py +9 -10
  17. uproot-5.7.4/tests/test_1609_tprofiles.py +307 -0
  18. uproot-5.7.4/tests/test_1622_bigfile_boundary_crossing.py +33 -0
  19. uproot-5.7.3/tests/test_1085_dask_write.py +0 -83
  20. {uproot-5.7.3 → uproot-5.7.4}/.all-contributorsrc +0 -0
  21. {uproot-5.7.3 → uproot-5.7.4}/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
  22. {uproot-5.7.3 → uproot-5.7.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  23. {uproot-5.7.3 → uproot-5.7.4}/.github/ISSUE_TEMPLATE/documentation.md +0 -0
  24. {uproot-5.7.3 → uproot-5.7.4}/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
  25. {uproot-5.7.3 → uproot-5.7.4}/.github/dependabot.yml +0 -0
  26. {uproot-5.7.3 → uproot-5.7.4}/.github/workflows/build-distributions.yml +0 -0
  27. {uproot-5.7.3 → uproot-5.7.4}/.github/workflows/deploy.yml +0 -0
  28. {uproot-5.7.3 → uproot-5.7.4}/.github/workflows/semantic-pr-title.yml +0 -0
  29. {uproot-5.7.3 → uproot-5.7.4}/.gitignore +0 -0
  30. {uproot-5.7.3 → uproot-5.7.4}/.readthedocs.yml +0 -0
  31. {uproot-5.7.3 → uproot-5.7.4}/CITATION.cff +0 -0
  32. {uproot-5.7.3 → uproot-5.7.4}/CONTRIBUTING.md +0 -0
  33. {uproot-5.7.3 → uproot-5.7.4}/LICENSE +0 -0
  34. {uproot-5.7.3 → uproot-5.7.4}/README.md +0 -0
  35. {uproot-5.7.3 → uproot-5.7.4}/codecov.yml +0 -0
  36. {uproot-5.7.3 → uproot-5.7.4}/dev/custom-interpretation/README.md +0 -0
  37. {uproot-5.7.3 → uproot-5.7.4}/dev/example-objects.py +0 -0
  38. {uproot-5.7.3 → uproot-5.7.4}/dev/make-models.py +0 -0
  39. {uproot-5.7.3 → uproot-5.7.4}/docs-img/diagrams/abstraction-layers.png +0 -0
  40. {uproot-5.7.3 → uproot-5.7.4}/docs-img/diagrams/abstraction-layers.svg +0 -0
  41. {uproot-5.7.3 → uproot-5.7.4}/docs-img/diagrams/example-dask-graph.png +0 -0
  42. {uproot-5.7.3 → uproot-5.7.4}/docs-img/diagrams/uproot-awkward-timeline.png +0 -0
  43. {uproot-5.7.3 → uproot-5.7.4}/docs-img/diagrams/uproot-awkward-timeline.svg +0 -0
  44. {uproot-5.7.3 → uproot-5.7.4}/docs-img/logo/logo-300px-white.png +0 -0
  45. {uproot-5.7.3 → uproot-5.7.4}/docs-img/logo/logo-300px.png +0 -0
  46. {uproot-5.7.3 → uproot-5.7.4}/docs-img/logo/logo-600px.png +0 -0
  47. {uproot-5.7.3 → uproot-5.7.4}/docs-img/logo/logo.svg +0 -0
  48. {uproot-5.7.3 → uproot-5.7.4}/docs-img/photos/switcheroo.jpg +0 -0
  49. {uproot-5.7.3 → uproot-5.7.4}/docs-sphinx/_templates/breadcrumbs.html +0 -0
  50. {uproot-5.7.3 → uproot-5.7.4}/docs-sphinx/conf.py +0 -0
  51. {uproot-5.7.3 → uproot-5.7.4}/docs-sphinx/index.rst +0 -0
  52. {uproot-5.7.3 → uproot-5.7.4}/docs-sphinx/make_changelog.py +0 -0
  53. {uproot-5.7.3 → uproot-5.7.4}/docs-sphinx/prepare_docstrings.py +0 -0
  54. {uproot-5.7.3 → uproot-5.7.4}/docs-sphinx/requirements.txt +0 -0
  55. {uproot-5.7.3 → uproot-5.7.4}/docs-sphinx/uproot3-to-4.rst +0 -0
  56. {uproot-5.7.3 → uproot-5.7.4}/pyproject.toml +0 -0
  57. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/__init__.py +0 -0
  58. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/_awkwardforth.py +0 -0
  59. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/_dask.py +0 -0
  60. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/_util.py +0 -0
  61. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behavior.py +0 -0
  62. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/RNTuple.py +0 -0
  63. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/RooCurve.py +0 -0
  64. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/RooHist.py +0 -0
  65. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TAxis.py +0 -0
  66. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TBranch.py +0 -0
  67. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TBranchElement.py +0 -0
  68. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TDatime.py +0 -0
  69. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TGraph.py +0 -0
  70. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TGraphAsymmErrors.py +0 -0
  71. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TGraphErrors.py +0 -0
  72. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TH1.py +0 -0
  73. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TH2.py +0 -0
  74. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TH2Poly.py +0 -0
  75. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TH3.py +0 -0
  76. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TParameter.py +0 -0
  77. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TProfile2D.py +0 -0
  78. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TProfile3D.py +0 -0
  79. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/TTree.py +0 -0
  80. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/behaviors/__init__.py +0 -0
  81. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/cache.py +0 -0
  82. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/compression.py +0 -0
  83. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/const.py +0 -0
  84. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/containers.py +0 -0
  85. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/deserialization.py +0 -0
  86. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/dynamic.py +0 -0
  87. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/exceptions.py +0 -0
  88. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/extras.py +0 -0
  89. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/interpretation/__init__.py +0 -0
  90. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/interpretation/custom.py +0 -0
  91. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/interpretation/grouped.py +0 -0
  92. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/interpretation/identify.py +0 -0
  93. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/interpretation/jagged.py +0 -0
  94. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/interpretation/known_forth/__init__.py +0 -0
  95. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/interpretation/known_forth/atlas.py +0 -0
  96. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/interpretation/library.py +0 -0
  97. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/interpretation/numerical.py +0 -0
  98. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/interpretation/objects.py +0 -0
  99. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/interpretation/strings.py +0 -0
  100. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/language/__init__.py +0 -0
  101. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/language/python.py +0 -0
  102. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/model.py +0 -0
  103. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/RNTuple.py +0 -0
  104. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TArray.py +0 -0
  105. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TAtt.py +0 -0
  106. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TBasket.py +0 -0
  107. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TBranch.py +0 -0
  108. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TClonesArray.py +0 -0
  109. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TDatime.py +0 -0
  110. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TGraph.py +0 -0
  111. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TH.py +0 -0
  112. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/THashList.py +0 -0
  113. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TLeaf.py +0 -0
  114. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TList.py +0 -0
  115. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TMatrixT.py +0 -0
  116. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TNamed.py +0 -0
  117. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TObjArray.py +0 -0
  118. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TObjString.py +0 -0
  119. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TObject.py +0 -0
  120. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TRef.py +0 -0
  121. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TString.py +0 -0
  122. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TTable.py +0 -0
  123. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TTime.py +0 -0
  124. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/TTree.py +0 -0
  125. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/models/__init__.py +0 -0
  126. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/pyroot.py +0 -0
  127. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/serialization.py +0 -0
  128. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/sink/__init__.py +0 -0
  129. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/sink/file.py +0 -0
  130. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/source/__init__.py +0 -0
  131. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/source/chunk.py +0 -0
  132. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/source/coalesce.py +0 -0
  133. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/source/cufile_interface.py +0 -0
  134. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/source/cursor.py +0 -0
  135. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/source/file.py +0 -0
  136. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/source/futures.py +0 -0
  137. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/source/http.py +0 -0
  138. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/source/object.py +0 -0
  139. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/source/xrootd.py +0 -0
  140. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/streamers.py +0 -0
  141. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/writing/__init__.py +0 -0
  142. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/writing/_cascadentuple.py +0 -0
  143. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/writing/_cascadetree.py +0 -0
  144. {uproot-5.7.3 → uproot-5.7.4}/src/uproot/writing/interpret.py +0 -0
  145. {uproot-5.7.3 → uproot-5.7.4}/tests/__init__.py +0 -0
  146. {uproot-5.7.3 → uproot-5.7.4}/tests/conftest.py +0 -0
  147. {uproot-5.7.3 → uproot-5.7.4}/tests/samples/h_dynamic.pkl +0 -0
  148. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0001_source_class.py +0 -0
  149. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0006_notify_when_downloaded.py +0 -0
  150. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0007_single_chunk_interface.py +0 -0
  151. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0008_start_interpretation.py +0 -0
  152. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0009_nested_directories.py +0 -0
  153. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0010_start_streamers.py +0 -0
  154. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0011_generate_classes_from_streamers.py +0 -0
  155. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0013_rntuple_anchor.py +0 -0
  156. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0014_all_ttree_versions.py +0 -0
  157. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0016_interpretations.py +0 -0
  158. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0017_multi_basket_multi_branch_fetch.py +0 -0
  159. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0018_array_fetching_interface.py +0 -0
  160. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0022_number_of_branches.py +0 -0
  161. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0023_more_interpretations_1.py +0 -0
  162. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0023_ttree_versions.py +0 -0
  163. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0028_fallback_to_read_streamer.py +0 -0
  164. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0029_more_string_types.py +0 -0
  165. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0031_test_stl_containers.py +0 -0
  166. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0033_more_interpretations_2.py +0 -0
  167. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0034_generic_objects_in_ttrees.py +0 -0
  168. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0035_datatype_generality.py +0 -0
  169. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0038_memberwise_serialization.py +0 -0
  170. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0043_iterate_function.py +0 -0
  171. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0044_concatenate_function.py +0 -0
  172. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0046_histograms_bh_hist.py +0 -0
  173. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0053_parents_should_not_be_bases.py +0 -0
  174. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0058_detach_model_objects_from_files.py +0 -0
  175. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0066_fix_http_fallback_freeze.py +0 -0
  176. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0067_common_entry_offsets.py +0 -0
  177. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0081_dont_parse_colons.py +0 -0
  178. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0087_memberwise_splitting_not_implemented_messages.py +0 -0
  179. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0088_read_with_http.py +0 -0
  180. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0099_read_from_file_object.py +0 -0
  181. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0112_fix_pandas_with_cut.py +0 -0
  182. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0118_fix_name_fetch_again.py +0 -0
  183. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0123_atlas_issues.py +0 -0
  184. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0126_turn_unknown_emptyarrays_into_known_types.py +0 -0
  185. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0167_use_the_common_histogram_interface.py +0 -0
  186. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0172_allow_allocators_in_vector_typenames.py +0 -0
  187. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0173_empty_and_multiprocessing_bugs.py +0 -0
  188. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0182_complain_about_missing_files.py +0 -0
  189. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0194_fix_lost_cuts_in_iterate.py +0 -0
  190. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0220_contiguous_byte_ranges_in_http.py +0 -0
  191. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0228_read_TProfiles.py +0 -0
  192. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0240_read_TGraphAsymmErrors.py +0 -0
  193. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0278_specializations_for_TParameter.py +0 -0
  194. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0302_pickle.py +0 -0
  195. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0303_empty_jagged_array.py +0 -0
  196. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0320_start_working_on_ROOT_writing.py +0 -0
  197. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0322_writablefile_infrastructure.py +0 -0
  198. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0329_update_existing_root_files.py +0 -0
  199. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0335_empty_ttree_division_by_zero.py +0 -0
  200. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0341_manipulate_streamer_info.py +0 -0
  201. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0344_writabledirectory_can_read.py +0 -0
  202. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0345_bulk_copy_method.py +0 -0
  203. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0349_write_TObjString.py +0 -0
  204. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0350_read_RooCurve_RooHist.py +0 -0
  205. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0351_write_TList.py +0 -0
  206. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0352_write_THashList.py +0 -0
  207. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0384_move_behavior_of_and_fix_383.py +0 -0
  208. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0398_dimensions_in_leaflist.py +0 -0
  209. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0405_write_a_histogram.py +0 -0
  210. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0406_write_a_ttree.py +0 -0
  211. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0407_read_TDatime.py +0 -0
  212. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0412_write_multidimensional_numpy_to_ttree.py +0 -0
  213. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0414_write_jagged_arrays.py +0 -0
  214. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0416_writing_compressed_data.py +0 -0
  215. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0418_read_TTable.py +0 -0
  216. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0420_pyroot_uproot_interoperability.py +0 -0
  217. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0422_hist_integration.py +0 -0
  218. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0430_global_index_for_tuples_of_DataFrames.py +0 -0
  219. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0438_TClonesArray_is_not_AsGrouped.py +0 -0
  220. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0439_check_awkward_before_numpy.py +0 -0
  221. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0442_regular_TClonesArray.py +0 -0
  222. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0472_tstreamerinfo_for_ttree.py +0 -0
  223. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0475_remember_to_update_freesegments.py +0 -0
  224. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0484_manually_add_model_for_TMatrixTSym_double_.py +0 -0
  225. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0487_implement_asdtypeinplace.py +0 -0
  226. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0498_create_leaf_branch_in_extend.py +0 -0
  227. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0519_remove_memmap_copy.py +0 -0
  228. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0520_dynamic_classes_cant_be_abc_subclasses.py +0 -0
  229. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0569_fBits_is_4_bytes.py +0 -0
  230. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0576_unicode_in_names.py +0 -0
  231. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0578_dask_for_numpy.py +0 -0
  232. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0580_round_trip_for_no_flow_histograms.py +0 -0
  233. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0589_explicitly_interpret_RVec_type.py +0 -0
  234. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0603_dask_delayed_open.py +0 -0
  235. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0609_num_enteries_func.py +0 -0
  236. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0610_awkward_form.py +0 -0
  237. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0630_rntuple_basics.py +0 -0
  238. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0637_setup_tests_for_AwkwardForth.py +0 -0
  239. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0643_reading_vector_pair_TLorentzVector_int.py +0 -0
  240. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0651_implement_transformed_axis.py +0 -0
  241. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0652_dask_for_awkward.py +0 -0
  242. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0662_rntuple_stl_containers.py +0 -0
  243. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0692_fsspec_reading.py +0 -0
  244. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0692_fsspec_writing.py +0 -0
  245. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0700_dask_empty_arrays.py +0 -0
  246. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0705_rntuple_writing_metadata.py +0 -0
  247. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0750_avoid_empty_TBasket_issue.py +0 -0
  248. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0755_dask_awkward_column_projection.py +0 -0
  249. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0791_protect_uproot_project_columns_from_dask_node_names.py +0 -0
  250. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0798_DAOD_PHYSLITE.py +0 -0
  251. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0808_fix_awkward_form_for_AsStridedObjects.py +0 -0
  252. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0816_separate_AwkwardForth_machines_by_TBranch.py +0 -0
  253. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0832_ak_add_doc_should_also_add_to_typetracer.py +0 -0
  254. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0840_support_tleafG.py +0 -0
  255. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0841_fix_814.py +0 -0
  256. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0844_fix_delete_hist_from_root.py +0 -0
  257. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0852_fix_strided_interp_extra_offsets.py +0 -0
  258. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0870_writing_arrays_of_type_unknown_fix_822.py +0 -0
  259. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0876_uproot_dask_blind_steps.py +0 -0
  260. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0886_fix_awkward_form_breadcrumbs.py +0 -0
  261. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0910_fix_906_members_non_numerical_branches.py +0 -0
  262. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0911_fix_interp_array_non_numerical_objs_issue_880.py +0 -0
  263. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0912_fix_pandas_and_double_nested_vectors_issue_885.py +0 -0
  264. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0916_read_from_s3.py +0 -0
  265. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0927_dont_assume_uproot_in_global_scope_in_TPython_Eval.py +0 -0
  266. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0930_expressions_in_pandas.py +0 -0
  267. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0940_feat_add_TLeafC_string_support.py +0 -0
  268. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0962_rntuple_update.py +0 -0
  269. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0965_inverted_axes_variances_hist_888.py +0 -0
  270. {uproot-5.7.3 → uproot-5.7.4}/tests/test_0976_path_object_split.py +0 -0
  271. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1043_const_std_string.py +0 -0
  272. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1058_dask_awkward_report.py +0 -0
  273. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1063_dask_distributed.py +0 -0
  274. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1070_pandas_dataframe_building_performance_fix.py +0 -0
  275. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1102_any_locks_in_models_must_be_transient.py +0 -0
  276. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1114_fix_attempt_to_concatenate_numpy_with_awkward.py +0 -0
  277. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1120_check_decompression_executor_pass_for_dask.py +0 -0
  278. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1127_fix_allow_colon_in_key_names.py +0 -0
  279. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1128_TGraph_writing.py +0 -0
  280. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1146_split_ranges_for_large_files_over_http.py +0 -0
  281. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1154_classof_using_relative_path.py +0 -0
  282. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1159_rntuple_cluster_groups.py +0 -0
  283. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1160_std_string_in_TDirectory.py +0 -0
  284. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1180_read_free_floating_vector_issue_1179.py +0 -0
  285. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1181_support_for_stl_list.py +0 -0
  286. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1182_add_support_for_bitset.py +0 -0
  287. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1183_ttime_custom.py +0 -0
  288. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1186_dtype_might_raise_ValueError.py +0 -0
  289. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1189_dask_failing_on_duplicate_keys.py +0 -0
  290. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1191_rntuple_fixes.py +0 -0
  291. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1198_coalesce.py +0 -0
  292. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1207_fix_title_of_TBranch_with_counter.py +0 -0
  293. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1212_dont_let_update_mess_up_file_version.py +0 -0
  294. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1221_AwkwardForth_bug.py +0 -0
  295. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1223_more_rntuple_types.py +0 -0
  296. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1229_const_in_typename.py +0 -0
  297. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1250_rntuple_improvements.py +0 -0
  298. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1254_test_threadpool_executor_for_dask.py +0 -0
  299. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1264_write_NumPy_array_of_strings.py +0 -0
  300. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1275_fix_TStreamerLoop_code_generation.py +0 -0
  301. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1282_add_known_forth_for_atlas.py +0 -0
  302. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1285_rntuple_multicluster_concatenation.py +0 -0
  303. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1318_dont_compare_big_endian_in_awkward.py +0 -0
  304. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1321_pandas_changed_api_again.py +0 -0
  305. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1347_rntuple_floats_suppressed_cols.py +0 -0
  306. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1356_basic_rntuple_writing.py +0 -0
  307. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1375_extend_ak_add_doc.py +0 -0
  308. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1395_rntuple_writing_lists_and_structs.py +0 -0
  309. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1406_improved_rntuple_methods.py +0 -0
  310. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1411_rntuple_physlite_ATLAS.py +0 -0
  311. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1412_rntuple_dask.py +0 -0
  312. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1465_ignorecase_extension.py +0 -0
  313. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1467_rntuple_akform_construction.py +0 -0
  314. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1476_rntuple_jagged_subfields.py +0 -0
  315. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1477_custom_interpretation.py +0 -0
  316. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1492_rntuple_hidden_keys.py +0 -0
  317. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1496_rntuple_write_index_arrays.py +0 -0
  318. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1503_rntuple_virtual_arrays.py +0 -0
  319. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1510_rntuple_v1010.py +0 -0
  320. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1556_default_rntuple_writing.py +0 -0
  321. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1573_out_of_bounds_slicing.py +0 -0
  322. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1589_rntuple_inheritance.py +0 -0
  323. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1591_rntuple_read_to_numpy.py +0 -0
  324. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1599_mktree_mkrntuple_with_subdir.py +0 -0
  325. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1601_freesegments_stale_allocation.py +0 -0
  326. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1603_num_entries.py +0 -0
  327. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1604_write_tuple_dtypes.py +0 -0
  328. {uproot-5.7.3 → uproot-5.7.4}/tests/test_1610_read_TMatrixTSym_from_ttree.py +0 -0
  329. {uproot-5.7.3 → uproot-5.7.4}/tests-cuda/test_0630_rntuple_basics.py +0 -0
  330. {uproot-5.7.3 → uproot-5.7.4}/tests-cuda/test_0662_rntuple_stl_containers.py +0 -0
  331. {uproot-5.7.3 → uproot-5.7.4}/tests-cuda/test_0962_rntuple_update.py +0 -0
  332. {uproot-5.7.3 → uproot-5.7.4}/tests-cuda/test_1159_rntuple_cluster_groups.py +0 -0
  333. {uproot-5.7.3 → uproot-5.7.4}/tests-cuda/test_1191_rntuple_fixes.py +0 -0
  334. {uproot-5.7.3 → uproot-5.7.4}/tests-cuda/test_1223_more_rntuple_types.py +0 -0
  335. {uproot-5.7.3 → uproot-5.7.4}/tests-cuda/test_1250_rntuple_improvements.py +0 -0
  336. {uproot-5.7.3 → uproot-5.7.4}/tests-cuda/test_1285_rntuple_multicluster_concatenation.py +0 -0
  337. {uproot-5.7.3 → uproot-5.7.4}/tests-cuda/test_1347_rntuple_floats_suppressed_cols.py +0 -0
  338. {uproot-5.7.3 → uproot-5.7.4}/tests-cuda/test_1411_rntuple_physlite_ATLAS.py +0 -0
  339. {uproot-5.7.3 → uproot-5.7.4}/tests-wasm/__init__.py +0 -0
  340. {uproot-5.7.3 → uproot-5.7.4}/tests-wasm/test_1272_basic_functionality.py +0 -0
  341. {uproot-5.7.3 → uproot-5.7.4}/tests-wasm/test_1365_awkwardforth_reading.py +0 -0
  342. {uproot-5.7.3 → uproot-5.7.4}/tests-wasm/utils.py +0 -0
@@ -16,7 +16,7 @@ jobs:
16
16
  fail-fast: false
17
17
  matrix:
18
18
  platform: [windows-latest, macos-latest, ubuntu-latest]
19
- python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
19
+ python-version: ['3.10', '3.14', 3.14 python-freethreading]
20
20
 
21
21
  runs-on: ${{ matrix.platform }}
22
22
  timeout-minutes: 30
@@ -39,10 +39,14 @@ jobs:
39
39
  conda-forge/label/python_rc::_python_rc
40
40
  python=${{ matrix.python-version }}
41
41
 
42
- - uses: astral-sh/setup-uv@v7
42
+ - name: Set PYTHON_GIL=0 for free-threaded builds
43
+ if: contains(matrix.python-version, 'python-freethreading')
44
+ run: echo "PYTHON_GIL=0" >> $GITHUB_ENV
45
+
46
+ - uses: astral-sh/setup-uv@v8.1.0
43
47
 
44
48
  - name: Check active Python version
45
- run: python -c "import sys; assert '.'.join(str(s) for s in sys.version_info[:2]) == '${{ matrix.python-version }}', f'{version} incorrect!'"
49
+ run: python -c "import sys; assert '.'.join(str(s) for s in sys.version_info[:2]) == '${{ matrix.python-version }}'.split()[0], f'{version} incorrect!'"
46
50
 
47
51
  - name: Install ROOT
48
52
  if: matrix.python-version == 3.10 && runner.os == 'Linux'
@@ -94,7 +98,7 @@ jobs:
94
98
  python-version: ${{ matrix.python-version }}
95
99
  allow-prereleases: true
96
100
 
97
- - uses: astral-sh/setup-uv@v7
101
+ - uses: astral-sh/setup-uv@v8.1.0
98
102
 
99
103
  - name: Pip install the package
100
104
  run: uv pip install --system -e. --group=dev
@@ -120,7 +124,7 @@ jobs:
120
124
  with:
121
125
  python-version: ${{ matrix.python-version }}
122
126
 
123
- - uses: astral-sh/setup-uv@v7
127
+ - uses: astral-sh/setup-uv@v8.1.0
124
128
 
125
129
  - name: Pip install the package
126
130
  run: |
@@ -148,7 +152,7 @@ jobs:
148
152
  with:
149
153
  python-version: '3.13'
150
154
 
151
- - uses: astral-sh/setup-uv@v7
155
+ - uses: astral-sh/setup-uv@v8.1.0
152
156
 
153
157
  - name: Install pyodide-build
154
158
  run: python3 -m pip install pyodide-build==$PYODIDE_BUILD_VERSION
@@ -162,7 +166,7 @@ jobs:
162
166
  echo "emsdk-version=$EMSCRIPTEN_VERSION" >> $GITHUB_OUTPUT
163
167
 
164
168
  - name: Install EMSDK
165
- uses: mymindstorm/setup-emsdk@v14
169
+ uses: mymindstorm/setup-emsdk@v16
166
170
  with:
167
171
  version: ${{ steps.compute-emsdk-version.outputs.emsdk-version }}
168
172
 
@@ -229,7 +233,6 @@ jobs:
229
233
  init-shell: bash
230
234
  create-args: >-
231
235
  -c rapidsai
232
- -c nvidia
233
236
  python=3.13
234
237
  cuda-version=${{ matrix.cuda-version }}
235
238
  cuda-toolkit
@@ -263,9 +266,10 @@ jobs:
263
266
 
264
267
  - name: Upload test results to Codecov
265
268
  if: ${{ !cancelled() && matrix.cuda-version == 13 }}
266
- uses: codecov/test-results-action@v1
269
+ uses: codecov/codecov-action@v6
267
270
  with:
268
271
  token: ${{ secrets.CODECOV_TOKEN }}
272
+ report_type: test_results
269
273
 
270
274
  pass:
271
275
  if: always()
@@ -33,7 +33,7 @@ jobs:
33
33
  run: ls -lha dist/*.whl
34
34
 
35
35
  - name: Upload wheel to Anaconda Cloud as nightly
36
- uses: scientific-python/upload-nightly-action@5748273c71e2d8d3a61f3a11a16421c8954f9ecf # 0.6.3
36
+ uses: scientific-python/upload-nightly-action@e76cfec8a4611fd02808a801b0ff5a7d7c1b2d99 # 0.6.4
37
37
  with:
38
38
  artifacts_path: dist
39
39
  anaconda_nightly_upload_token: ${{ secrets.ANACONDA_ORG_UPLOAD_TOKEN }}
@@ -19,12 +19,12 @@ repos:
19
19
  - id: trailing-whitespace
20
20
 
21
21
  - repo: https://github.com/psf/black-pre-commit-mirror
22
- rev: 26.1.0
22
+ rev: 26.3.1
23
23
  hooks:
24
24
  - id: black
25
25
 
26
26
  - repo: https://github.com/astral-sh/ruff-pre-commit
27
- rev: v0.15.4
27
+ rev: v0.15.9
28
28
  hooks:
29
29
  - id: ruff-check
30
30
  args: [--fix, --show-fixes]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uproot
3
- Version: 5.7.3
3
+ Version: 5.7.4
4
4
  Summary: ROOT I/O in pure Python and NumPy.
5
5
  Project-URL: Download, https://github.com/scikit-hep/uproot5/releases
6
6
  Project-URL: Homepage, https://github.com/scikit-hep/uproot5
@@ -924,6 +924,8 @@ Reading RNTuples
924
924
 
925
925
  TTree has been the default format to store large datasets in ROOT files for decades. However, it has slowly become outdated and is not optimized for modern systems. This is where the RNTuple format comes in. It is a modern serialization format that is designed with modern systems in mind and is planned to replace TTree in the coming years. `Version 1.0.0.0 <https://cds.cern.ch/record/2923186>`__ is out and will be supported "forever".
926
926
 
927
+ Starting in Uproot v5.7.0, RNTuple is the default format for writing. When you use the dict-like syntax to write data to a file, Uproot will create an RNTuple instead of a TTree.
928
+
927
929
  RNTuples are deliberately simpler than TTrees by design. For the first time, there’s an official specification, making it much easier for third-party I/O tools like Uproot to support it. Uproot already supports reading the full RNTuple specification, meaning that you can read any RNTuple you find in the wild. It also already supports writing a large part of the specification, and intends to support as much as it makes sense for data analysis.
928
930
 
929
931
  To ease the transition into RNTuples, we are designing the interface to closely match the existing TTree interface. Many of the functionality explained in the previous subsections works in the same way. However, there the terminology is slightly different (e.g. "branch" becomes "field") and arguments may vary slightly, accordingly.
@@ -1145,8 +1147,10 @@ Writing TTrees to a file
1145
1147
  TTrees are a special type of object, just as TDirectories are special: data can be cumulatively added to them.
1146
1148
 
1147
1149
  :doc:`uproot.writing.writable.WritableTree` objects can be created using the :ref:`uproot.writing.writable.WritableDirectory.mktree` method that Uproot provides for TDirectories.
1148
- Previously, they could be created by assigning TTree-like data to a name in a directory (e.g., ``file["tree"] = {"branch": np.arange(1000)}``). However, this syntax was deprecated,
1149
- as Uproot will switch to writing RNTuples with syntax, since the HEP community is moving towards RNTuples.
1150
+
1151
+ .. note::
1152
+
1153
+ Starting in v5.7.0, Uproot uses RNTuples as the default format for writing data when using the dict-like assignment syntax (e.g., ``file["my_data"] = {"my_array": np.arange(1000)}``). If you specifically want to write a TTree, you should use the :ref:`uproot.writing.writable.WritableDirectory.mktree` method.
1150
1154
 
1151
1155
  .. code-block:: python
1152
1156
 
@@ -1327,14 +1331,21 @@ Writing RNTuples
1327
1331
 
1328
1332
  Just like with reading, writing RNTuples is similar to writing TTree objects. Since RNTuples are much simpler, we aim to be able to write almost any RNTuple that you might want.
1329
1333
 
1330
- Here is an example of writing an RNTuple. Since TTree is still the default format for the near future, writing an RNTuple is a bit more verbose.
1334
+ RNTuples are the default format for writing data starting in Uproot v5.7.0. You can write an RNTuple by using a dict-like syntax:
1331
1335
 
1332
1336
  .. code-block:: python
1333
1337
 
1334
1338
  >>> file = uproot.recreate("example.root")
1335
1339
  >>> data = {"my_int": [1,2], "my_vector": [[1,2], [3,4,5]]}
1336
- >>> rntuple = file.mkrntuple("my_rntuple", data)
1337
- >>> rntuple.extend(data) # Can be extended, just like TTrees
1340
+ >>> file["my_rntuple"] = data
1341
+ >>> file["my_rntuple"].extend(data) # Can be extended, just like TTrees
1342
+
1343
+ You can also use the :ref:`uproot.writing.writable.WritableDirectory.mkrntuple` method for more explicit RNTuple creation, and to have the ability to initialize an empty RNTuple from a type specification dictionary or an Awkward form.
1344
+
1345
+ .. code-block:: python
1346
+
1347
+ >>> file.mkrntuple("ntuple", {"x": "f4", "y": "var * int64"})
1348
+ <WritableNTuple '/ntuple' at 0x000131ff30e0>
1338
1349
 
1339
1350
  Using your own interpretation
1340
1351
  --------------------------------
@@ -103,11 +103,11 @@ def _values_errors_1d(error_mode, fBinEntries, root_cont, fSumw2, fNcells, fBinS
103
103
 
104
104
  root_neff = _effective_counts_1d(fBinEntries, fBinSumw2, fNcells)
105
105
 
106
- root_eprim2 = numpy.zeros(len(root_cont), dtype=numpy.float64)
107
- root_eprim2[nonzero] = abs(
106
+ root_eprisum_sq_dev = numpy.zeros(len(root_cont), dtype=numpy.float64)
107
+ root_eprisum_sq_dev[nonzero] = abs(
108
108
  root_err2[nonzero] / root_sum[nonzero] - root_contsum[nonzero] ** 2
109
109
  )
110
- root_eprim = numpy.sqrt(root_eprim2)
110
+ root_eprim = numpy.sqrt(root_eprisum_sq_dev)
111
111
 
112
112
  if error_mode == _kERRORSPREADI:
113
113
  numer = numpy.ones(len(root_cont), dtype=numpy.float64)
@@ -237,7 +237,7 @@ class TProfile(Profile):
237
237
  @property
238
238
  def weighted(self):
239
239
  fBinSumw2 = self.member("fBinSumw2", none_if_missing=True)
240
- return fBinSumw2 is None or len(fBinSumw2) != len(self.member("fNcells"))
240
+ return fBinSumw2 is not None and len(fBinSumw2) == self.member("fNcells")
241
241
 
242
242
  def counts(self, flow=True):
243
243
  out = _effective_counts_1d(
@@ -298,40 +298,76 @@ class TProfile(Profile):
298
298
  boost_histogram = uproot.extras.boost_histogram()
299
299
 
300
300
  effective_counts = self.counts(flow=True)
301
- _, errors = self._values_errors(True, self.member("fErrorMode"))
302
- values = self._bases[0]._bases[-1]
303
- variances = numpy.square(errors)
304
- sum_of_bin_weights = numpy.asarray(self.member("fBinEntries"))
301
+ sum_of_bin_weights = numpy.asarray(
302
+ self.member("fBinEntries"), dtype=numpy.float64
303
+ )
304
+ raw_values = numpy.asarray(self._bases[0]._bases[-1], dtype=numpy.float64)
305
+ fSumw2_member = self.member("fSumw2", none_if_missing=True)
306
+ fNcells = self.member("fNcells")
307
+
308
+ # Compute mean = sum(y) / count (ROOT TProfile stores sum(y) in the TArray)
309
+ nonzero = sum_of_bin_weights != 0
310
+ mean_values = numpy.zeros(len(raw_values), dtype=numpy.float64)
311
+ mean_values[nonzero] = raw_values[nonzero] / sum_of_bin_weights[nonzero]
312
+
313
+ # Compute sum_sq_dev = sum(y^2) - count * mean^2 directly from fSumw2.
314
+ # fErrorMode is intentionally ignored here: it controls how ROOT displays
315
+ # bin errors but does not change the underlying data. boost-hostogram's
316
+ # storage has a fixed meaning for _sum_of_weighted_deltas_squared,
317
+ # so we can't change it based on fErrorMode.
318
+ if fSumw2_member is not None:
319
+ fSumw2 = numpy.asarray(fSumw2_member, dtype=numpy.float64)
320
+ else:
321
+ fSumw2 = numpy.array([], dtype=numpy.float64)
322
+ if len(fSumw2) == fNcells:
323
+ sum_sq_dev = numpy.maximum(
324
+ fSumw2 - sum_of_bin_weights * mean_values**2, 0.0
325
+ )
326
+ else:
327
+ sum_sq_dev = numpy.zeros(len(raw_values), dtype=numpy.float64)
305
328
 
306
- storage = boost_histogram.storage.WeightedMean()
329
+ if self.weighted:
330
+ storage = boost_histogram.storage.WeightedMean()
331
+ else:
332
+ storage = boost_histogram.storage.Mean()
307
333
 
308
334
  xaxis = uproot.behaviors.TH1._boost_axis(self.member("fXaxis"), axis_metadata)
309
335
  out = boost_histogram.Histogram(xaxis, storage=storage)
310
336
  for k, v in metadata.items():
311
337
  setattr(out, k, self.member(v))
312
338
 
313
- if isinstance(xaxis, boost_histogram.axis.StrCategory):
339
+ if self.member("fXaxis").member("fLabels") is not None:
340
+ # ROOT's categorical axes (with fLabels) always have an underflow bin (bin 0).
341
+ # boost-histogram's Category axes do not have underflow.
342
+ # We slice off the first ROOT bin (underflow) to align with boost-histogram.
314
343
  effective_counts = effective_counts[1:]
315
- values = values[1:]
316
- variances = variances[1:]
344
+ mean_values = mean_values[1:]
345
+ sum_sq_dev = sum_sq_dev[1:]
317
346
  sum_of_bin_weights = sum_of_bin_weights[1:]
318
347
 
319
- out.metadata = {"fSumw2": self.member("fSumw2")}
348
+ # TODO: This should only be needed for weighted storage, but there seems to be some bug in Uproot's serialization of fBinSumw2
349
+ # that causes weighted TProfiles to appear unweighted when read back in.
350
+ out.metadata = {
351
+ "fEntries": self.member("fEntries"),
352
+ }
320
353
  view = out.view(flow=True)
321
354
 
322
355
  # https://github.com/root-project/root/blob/ffc7c588ac91aca30e75d356ea971129ee6a836a/hist/hist/src/TProfileHelper.h#L668-L671
323
- with numpy.errstate(divide="ignore", invalid="ignore"):
324
- sum_of_bin_weights_squared = (sum_of_bin_weights**2) / effective_counts
325
-
326
- # TODO: Drop this when boost-histogram has a way to set using the constructor.
327
- # New version should look something like this:
328
- # view[...] = np.stack(sum_of_bin_weights, sum_of_bin_weights_squared, values, variances)
329
- # Current / classic version:
330
- view["sum_of_weights"] = sum_of_bin_weights
331
- view["sum_of_weights_squared"] = sum_of_bin_weights_squared
332
- view["value"] = values
333
- view["_sum_of_weighted_deltas_squared"] = variances * (
334
- sum_of_bin_weights - sum_of_bin_weights_squared / sum_of_bin_weights
335
- )
356
+ if self.weighted:
357
+ with numpy.errstate(divide="ignore", invalid="ignore"):
358
+ sum_of_bin_weights_squared = (sum_of_bin_weights**2) / effective_counts
359
+
360
+ # TODO: Drop this when boost-histogram has a way to set using the constructor.
361
+ # New version should look something like this:
362
+ # view[...] = np.stack(sum_of_bin_weights, sum_of_bin_weights_squared, mean_values, sum_sq_dev)
363
+ # Current / classic version:
364
+ view["sum_of_weights"] = sum_of_bin_weights
365
+ view["sum_of_weights_squared"] = sum_of_bin_weights_squared
366
+ view["value"] = mean_values
367
+ view["_sum_of_weighted_deltas_squared"] = sum_sq_dev
368
+ else:
369
+ view["count"] = sum_of_bin_weights
370
+ view["value"] = mean_values
371
+ view["_sum_of_deltas_squared"] = sum_sq_dev
336
372
 
337
373
  return out
@@ -646,11 +646,15 @@ in file {file_path}""")
646
646
  :ref:`uproot.reading.ReadOnlyFile.object_cache` would still be
647
647
  accessible.
648
648
  """
649
- self._source.close()
649
+ if hasattr(self, "_source") and hasattr(self._source, "close"):
650
+ self._source.close()
650
651
  if hasattr(self._decompression_executor, "shutdown"):
651
- getattr(self._decompression_executor, "shutdown", None)()
652
+ self._decompression_executor.shutdown()
652
653
  if hasattr(self._interpretation_executor, "shutdown"):
653
- getattr(self._interpretation_executor, "shutdown", None)()
654
+ self._interpretation_executor.shutdown()
655
+
656
+ def __del__(self):
657
+ self.close()
654
658
 
655
659
  @property
656
660
  def closed(self):
@@ -674,11 +678,12 @@ in file {file_path}""")
674
678
  return self
675
679
 
676
680
  def __exit__(self, exception_type, exception_value, traceback):
677
- self._source.__exit__(exception_type, exception_value, traceback)
681
+ if hasattr(self, "_source") and hasattr(self._source, "__exit__"):
682
+ self._source.__exit__(exception_type, exception_value, traceback)
678
683
  if hasattr(self._decompression_executor, "shutdown"):
679
- getattr(self._decompression_executor, "shutdown", None)()
684
+ self._decompression_executor.shutdown()
680
685
  if hasattr(self._interpretation_executor, "shutdown"):
681
- getattr(self._interpretation_executor, "shutdown", None)()
686
+ self._interpretation_executor.shutdown()
682
687
 
683
688
  @property
684
689
  def source(self):
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import asyncio
6
6
  import concurrent.futures
7
+ import contextlib
7
8
  import queue
8
9
  import re
9
10
 
@@ -55,20 +56,20 @@ class FSSpecSource(uproot.source.chunk.Source):
55
56
 
56
57
  file_path = _maybe_wrap_remote_url(file_path)
57
58
 
58
- fsspec_options = {
59
+ self._fsspec_options = {
59
60
  k: v for k, v in options.items() if k not in uproot.reading.open.defaults
60
61
  }
61
- self._fs, self._file_path = fsspec.core.url_to_fs(file_path, **fsspec_options)
62
-
63
- # What should we do when there is a chain of filesystems?
64
- self._async_impl = self._fs.async_impl
65
-
62
+ self._file_path_orig = file_path
66
63
  self._open()
67
64
 
68
- self.__enter__()
69
-
70
65
  def _open(self):
71
66
  self._executor = FSSpecLoopExecutor()
67
+ self._open_file = fsspec.open(self._file_path_orig, **self._fsspec_options)
68
+ self._fs = self._open_file.fs
69
+ self._file_path = self._open_file.path
70
+ self._fo = self._open_file.__enter__()
71
+ self._async_impl = self._fs.async_impl
72
+ self._closed = False
72
73
 
73
74
  def __repr__(self):
74
75
  path = repr(self._file_path)
@@ -79,6 +80,9 @@ class FSSpecSource(uproot.source.chunk.Source):
79
80
  def __getstate__(self):
80
81
  state = dict(self.__dict__)
81
82
  state.pop("_executor")
83
+ state.pop("_open_file")
84
+ state.pop("_fo")
85
+ state.pop("_fs")
82
86
  return state
83
87
 
84
88
  def __setstate__(self, state):
@@ -90,6 +94,19 @@ class FSSpecSource(uproot.source.chunk.Source):
90
94
 
91
95
  def __exit__(self, exception_type, exception_value, traceback):
92
96
  self._executor.shutdown()
97
+ if not self._closed:
98
+ self._open_file.__exit__(exception_type, exception_value, traceback)
99
+
100
+ # Workaround for leaking fsspec filesystems (like ZipFileSystem/TarFileSystem)
101
+ # that don't correctly close their underlying file objects.
102
+ if hasattr(self._fs, "close"):
103
+ with contextlib.suppress(Exception):
104
+ self._fs.close()
105
+ if hasattr(self._fs, "of") and hasattr(self._fs.of, "__exit__"):
106
+ with contextlib.suppress(Exception):
107
+ self._fs.of.__exit__(None, None, None)
108
+
109
+ self._closed = True
93
110
 
94
111
  def chunk(self, start: int, stop: int) -> uproot.source.chunk.Chunk:
95
112
  """
@@ -199,8 +216,7 @@ class FSSpecSource(uproot.source.chunk.Source):
199
216
  True if the associated file/connection/thread pool is closed; False
200
217
  otherwise.
201
218
  """
202
- # FSSpecSource uses entirely stateless interfaces
203
- return False
219
+ return self._closed
204
220
 
205
221
 
206
222
  class FSSpecLoopExecutor(uproot.source.futures.Executor):
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '5.7.3'
22
- __version_tuple__ = version_tuple = (5, 7, 3)
21
+ __version__ = version = '5.7.4'
22
+ __version_tuple__ = version_tuple = (5, 7, 4)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -451,6 +451,28 @@ _free_format_small = struct.Struct(">HII")
451
451
  _free_format_big = struct.Struct(">HQQ")
452
452
 
453
453
 
454
+ def _slices_bytes(slices):
455
+ total = 0
456
+ for _, stop in slices:
457
+ if stop - 1 >= uproot.const.kStartBigFile:
458
+ total += _free_format_big.size
459
+ else:
460
+ total += _free_format_small.size
461
+ return total
462
+
463
+
464
+ def _free_segments_num_bytes(slices, file_end, data_location=0):
465
+ total = _slices_bytes(slices)
466
+
467
+ if file_end is None:
468
+ file_end = (data_location or 0) + total + _free_format_small.size
469
+
470
+ if file_end >= uproot.const.kStartBigFile:
471
+ return total + _free_format_big.size
472
+ else:
473
+ return total + _free_format_small.size
474
+
475
+
454
476
  class FreeSegmentsData(CascadeLeaf):
455
477
  """
456
478
  A :doc:`uproot.writing._cascade.CascadeLeaf` for the FreeSegments record
@@ -502,24 +524,12 @@ class FreeSegmentsData(CascadeLeaf):
502
524
 
503
525
  @property
504
526
  def num_bytes(self):
505
- total = 0
506
- for _, stop in self._slices:
507
- if stop - 1 >= uproot.const.kStartBigFile:
508
- total += _free_format_big.size
509
- else:
510
- total += _free_format_small.size
511
-
512
- if self._end is None:
513
- if total + _free_format_small.size >= uproot.const.kStartBigFile:
514
- total += _free_format_big.size
515
- else:
516
- total += _free_format_small.size
517
- elif self._end >= uproot.const.kStartBigFile:
518
- total += _free_format_big.size
519
- else:
520
- total += _free_format_small.size
527
+ return _free_segments_num_bytes(self._slices, self._end, self._location)
521
528
 
522
- return total
529
+ def required_end(self, data_location):
530
+ return data_location + _free_segments_num_bytes(
531
+ self._slices, None, data_location
532
+ )
523
533
 
524
534
  def serialize(self):
525
535
  pairs = []
@@ -660,8 +670,8 @@ class FreeSegments(CascadeNode):
660
670
  out = self._key.location
661
671
  if not dry_run:
662
672
  self._key.location = self._key.location + num_bytes
663
- self._data.end = (
664
- self._key.location + self._key.allocation + self._data.allocation
673
+ self._data.end = self._data.required_end(
674
+ self._key.location + self._key.num_bytes
665
675
  )
666
676
  return out
667
677
 
@@ -707,25 +717,18 @@ class FreeSegments(CascadeNode):
707
717
 
708
718
  @staticmethod
709
719
  def _slices_bytes(slices):
710
- total = 0
711
- for _, stop in slices:
712
- if stop - 1 >= uproot.const.kStartBigFile:
713
- total += _free_format_big.size
714
- else:
715
- total += _free_format_small.size
716
- return total
720
+ return _slices_bytes(slices)
717
721
 
718
722
  def release(self, start, stop):
719
723
  new_slices = self._another_slice(self._data.slices, start, stop)
720
724
 
721
725
  if self.at_end:
722
726
  self._data.slices = new_slices
723
- self._data.allocation = None
727
+ self._data.end = self._data.required_end(
728
+ self._key.location + self._key.num_bytes
729
+ )
724
730
  self._key.uncompressed_bytes = self._data.allocation
725
731
  self._key.compressed_bytes = self._key.uncompressed_bytes
726
- self._data.end = (
727
- self._key.location + self._key.allocation + self._key.uncompressed_bytes
728
- )
729
732
 
730
733
  elif self._slices_bytes(new_slices) <= self._slices_bytes(self._data.slices):
731
734
  # Wherever the FreeSegments record is, it's not getting bigger.
@@ -744,12 +747,12 @@ class FreeSegments(CascadeNode):
744
747
  self._key.location,
745
748
  self._key.location + self._key.allocation + self._data.allocation,
746
749
  )
747
- self._data.allocation = None
750
+ self._key.location = self._data.end
751
+ self._data.end = self._data.required_end(
752
+ self._key.location + self._key.num_bytes
753
+ )
748
754
  self._key.uncompressed_bytes = self._data.allocation
749
755
  self._key.compressed_bytes = self._key.uncompressed_bytes
750
- self._key.location = self._data.end
751
- self._data.location = self._key.location + self._key.allocation
752
- self._data.end = self._data.location + self._key.uncompressed_bytes
753
756
 
754
757
  def write(self, sink):
755
758
  self._key.uncompressed_bytes = self._data.allocation
@@ -176,19 +176,22 @@ def ak_to_root(
176
176
  **(storage_options or {}),
177
177
  )
178
178
 
179
- branch_types = {name: array[name].type for name in array.fields}
180
-
181
- out_file.mktree(
182
- tree_name,
183
- branch_types,
184
- title=title,
185
- counter_name=counter_name,
186
- field_name=field_name,
187
- initial_basket_capacity=initial_basket_capacity,
188
- resize_factor=resize_factor,
189
- )
179
+ try:
180
+ branch_types = {name: array[name].type for name in array.fields}
181
+
182
+ out_file.mktree(
183
+ tree_name,
184
+ branch_types,
185
+ title=title,
186
+ counter_name=counter_name,
187
+ field_name=field_name,
188
+ initial_basket_capacity=initial_basket_capacity,
189
+ resize_factor=resize_factor,
190
+ )
190
191
 
191
- out_file[tree_name].extend({name: array[name] for name in array.fields})
192
+ out_file[tree_name].extend({name: array[name] for name in array.fields})
193
+ finally:
194
+ out_file.close()
192
195
 
193
196
 
194
197
  def none_to_none(*_):