nab-python 0.0.3__tar.gz → 0.0.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 (186) hide show
  1. {nab_python-0.0.3 → nab_python-0.0.4}/PKG-INFO +3 -3
  2. nab_python-0.0.4/benchmarks/_profile_runner.py +139 -0
  3. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/canary.py +15 -4
  4. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/ai-stack-lowest-direct.toml +8 -2
  5. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/ai-stack-lowest.toml +8 -2
  6. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/ai-stack.toml +8 -2
  7. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/airflow-lowest-direct.toml +16 -17
  8. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/airflow-lowest.toml +14 -17
  9. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/airflow.toml +14 -17
  10. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/pip-lowest-direct.toml +6 -3
  11. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/pip-lowest.toml +6 -3
  12. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/pip.toml +6 -3
  13. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/universal.toml +16 -0
  14. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios.py +21 -5
  15. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/strategy_sweep.py +7 -3
  16. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/universal_scenarios.py +6 -2
  17. {nab_python-0.0.3 → nab_python-0.0.4}/pyproject.toml +3 -3
  18. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_build/runner.py +14 -3
  19. nab_python-0.0.4/src/nab_python/_conflict_kind.py +20 -0
  20. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_lockfile/builder.py +158 -30
  21. nab_python-0.0.4/src/nab_python/_lockfile/disjointness.py +407 -0
  22. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_lockfile/pylock.py +205 -29
  23. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_lockfile/requirements.py +8 -7
  24. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_provider/extras.py +7 -7
  25. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_provider/listing.py +29 -9
  26. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_provider/metadata_resolver.py +24 -10
  27. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_testing/coordinator_fake.py +12 -4
  28. nab_python-0.0.4/src/nab_python/_toml.py +16 -0
  29. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/PROVENANCE.md +2 -2
  30. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/_range_utils.py +337 -112
  31. nab_python-0.0.4/src/nab_python/_vendor/packaging/_version_utils.py +90 -0
  32. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/metadata.py +19 -4
  33. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/pylock.py +1 -0
  34. nab_python-0.0.4/src/nab_python/_vendor/packaging/ranges.py +2112 -0
  35. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/specifiers.py +291 -159
  36. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/tags.py +8 -6
  37. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/config.py +609 -11
  38. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/download.py +39 -9
  39. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/fetch.py +60 -15
  40. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/lockfile.py +56 -0
  41. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/metadata.py +23 -0
  42. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/provider.py +77 -33
  43. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/requirements_file.py +100 -15
  44. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/resolve.py +444 -30
  45. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/universal/matrix.py +130 -33
  46. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/universal/provider.py +20 -5
  47. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/universal/reresolve.py +1 -0
  48. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/universal/resolve.py +230 -32
  49. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/universal/validate.py +8 -15
  50. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/universal/wheel_selection.py +92 -57
  51. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/workspace.py +8 -2
  52. nab_python-0.0.4/tests/property_python/test_lockfile_pep751.py +486 -0
  53. {nab_python-0.0.3 → nab_python-0.0.4}/tests/property_python/test_multi_index_pep503.py +6 -2
  54. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_async_transports.py +121 -39
  55. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_build_runner.py +144 -8
  56. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_cached_client.py +261 -0
  57. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_config.py +645 -1
  58. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_download.py +81 -4
  59. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_fetch.py +44 -30
  60. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_local_index.py +34 -4
  61. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_lockfile.py +1024 -75
  62. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_metadata.py +34 -1
  63. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_multi_index.py +5 -1
  64. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_provider.py +206 -12
  65. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_requirements_file.py +115 -28
  66. nab_python-0.0.4/tests/test_resolve.py +2534 -0
  67. nab_python-0.0.4/tests/test_simple_client_filenames.py +107 -0
  68. nab_python-0.0.4/tests/test_simple_client_hashes.py +25 -0
  69. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_vcs.py +51 -0
  70. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_workspace.py +57 -4
  71. {nab_python-0.0.3 → nab_python-0.0.4}/tests/universal/property_universal/test_provider_pep425.py +8 -10
  72. nab_python-0.0.4/tests/universal/test_matrix.py +519 -0
  73. nab_python-0.0.4/tests/universal/test_resolve.py +1375 -0
  74. {nab_python-0.0.3 → nab_python-0.0.4}/tests/universal/test_universal_provider.py +51 -11
  75. {nab_python-0.0.3 → nab_python-0.0.4}/tests/universal/test_validate.py +15 -0
  76. {nab_python-0.0.3 → nab_python-0.0.4}/tests/universal/test_wheel_selection.py +90 -0
  77. nab_python-0.0.3/benchmarks/_profile_runner.py +0 -120
  78. nab_python-0.0.3/benchmarks/strategy_sweep_results/summary.before-build-policy.json +0 -21937
  79. nab_python-0.0.3/benchmarks/strategy_sweep_results/summary.session28-baseline.json +0 -21970
  80. nab_python-0.0.3/benchmarks/strategy_sweep_results_fix12/summary.json +0 -21965
  81. nab_python-0.0.3/src/nab_python/_lockfile/disjointness.py +0 -207
  82. nab_python-0.0.3/src/nab_python/_vendor/packaging/_version_utils.py +0 -37
  83. nab_python-0.0.3/src/nab_python/_vendor/packaging/ranges.py +0 -1143
  84. nab_python-0.0.3/tests/property_python/test_lockfile_pep751.py +0 -263
  85. nab_python-0.0.3/tests/test_resolve.py +0 -1165
  86. nab_python-0.0.3/tests/universal/test_matrix.py +0 -258
  87. nab_python-0.0.3/tests/universal/test_resolve.py +0 -672
  88. {nab_python-0.0.3 → nab_python-0.0.4}/.gitignore +0 -0
  89. {nab_python-0.0.3 → nab_python-0.0.4}/LICENSE +0 -0
  90. {nab_python-0.0.3 → nab_python-0.0.4}/README.md +0 -0
  91. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/README.md +0 -0
  92. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/cache/.gitignore +0 -0
  93. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/canary_results/.gitignore +0 -0
  94. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/compare.py +0 -0
  95. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/results/.gitignore +0 -0
  96. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/big-packages-lowest-direct.toml +0 -0
  97. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/big-packages-lowest.toml +0 -0
  98. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/big-packages.toml +0 -0
  99. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/cross-tracker-lowest-direct.toml +0 -0
  100. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/cross-tracker-lowest.toml +0 -0
  101. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/cross-tracker.toml +0 -0
  102. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/ecosystem-lowest-direct.toml +0 -0
  103. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/ecosystem-lowest.toml +0 -0
  104. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/ecosystem.toml +0 -0
  105. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/forums-lowest-direct.toml +0 -0
  106. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/forums-lowest.toml +0 -0
  107. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/forums.toml +0 -0
  108. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/pdm-lowest-direct.toml +0 -0
  109. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/pdm-lowest.toml +0 -0
  110. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/pdm.toml +0 -0
  111. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/poetry-lowest-direct.toml +0 -0
  112. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/poetry-lowest.toml +0 -0
  113. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/poetry.toml +0 -0
  114. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/pytorch-lowest-direct.toml +0 -0
  115. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/pytorch-lowest.toml +0 -0
  116. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/pytorch.toml +0 -0
  117. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/quick-lowest-direct.toml +0 -0
  118. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/quick-lowest.toml +0 -0
  119. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/quick.toml +0 -0
  120. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/rip-lowest-direct.toml +0 -0
  121. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/rip-lowest.toml +0 -0
  122. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/rip.toml +0 -0
  123. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/unsupported-lowest-direct.toml +0 -0
  124. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/unsupported-lowest.toml +0 -0
  125. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/unsupported.toml +0 -0
  126. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/uv-lowest-direct.toml +0 -0
  127. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/uv-lowest.toml +0 -0
  128. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/scenarios/uv.toml +0 -0
  129. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/strategy_sweep_results/summary.json +0 -0
  130. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/strategy_sweep_summary.py +0 -0
  131. {nab_python-0.0.3 → nab_python-0.0.4}/benchmarks/universal_summary.py +0 -0
  132. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/__init__.py +0 -0
  133. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_build/__init__.py +0 -0
  134. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_build/env.py +0 -0
  135. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_build/errors.py +0 -0
  136. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_lockfile/__init__.py +0 -0
  137. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_packaging_provider.py +0 -0
  138. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_provider/__init__.py +0 -0
  139. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_provider/build_remote.py +0 -0
  140. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_provider/lookahead.py +0 -0
  141. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_provider/priority.py +0 -0
  142. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_provider/sources.py +0 -0
  143. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_testing/__init__.py +0 -0
  144. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vcs_admission.py +0 -0
  145. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/__init__.py +0 -0
  146. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/LICENSE +0 -0
  147. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/LICENSE.APACHE +0 -0
  148. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/LICENSE.BSD +0 -0
  149. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/__init__.py +0 -0
  150. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/_elffile.py +0 -0
  151. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/_manylinux.py +0 -0
  152. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/_musllinux.py +0 -0
  153. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/_parser.py +0 -0
  154. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/_structures.py +0 -0
  155. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/_tokenizer.py +0 -0
  156. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/dependency_groups.py +0 -0
  157. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/direct_url.py +0 -0
  158. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/errors.py +0 -0
  159. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/licenses/__init__.py +0 -0
  160. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/licenses/_spdx.py +0 -0
  161. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/markers.py +0 -0
  162. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/py.typed +0 -0
  163. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/requirements.py +0 -0
  164. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/utils.py +0 -0
  165. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/_vendor/packaging/version.py +0 -0
  166. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/build_backend.py +0 -0
  167. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/py.typed +0 -0
  168. {nab_python-0.0.3 → nab_python-0.0.4}/src/nab_python/universal/__init__.py +0 -0
  169. {nab_python-0.0.3 → nab_python-0.0.4}/tests/__init__.py +0 -0
  170. {nab_python-0.0.3 → nab_python-0.0.4}/tests/property_python/__init__.py +0 -0
  171. {nab_python-0.0.3 → nab_python-0.0.4}/tests/property_python/strategies.py +0 -0
  172. {nab_python-0.0.3 → nab_python-0.0.4}/tests/property_python/test_extras_pep685.py +0 -0
  173. {nab_python-0.0.3 → nab_python-0.0.4}/tests/property_python/test_marker_overlay.py +0 -0
  174. {nab_python-0.0.3 → nab_python-0.0.4}/tests/property_python/test_resolver_pep440.py +0 -0
  175. {nab_python-0.0.3 → nab_python-0.0.4}/tests/ruff.toml +0 -0
  176. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_build_backend.py +0 -0
  177. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_cache.py +0 -0
  178. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_resolver_packaging.py +0 -0
  179. {nab_python-0.0.3 → nab_python-0.0.4}/tests/test_vcs_admission.py +0 -0
  180. {nab_python-0.0.3 → nab_python-0.0.4}/tests/universal/__init__.py +0 -0
  181. {nab_python-0.0.3 → nab_python-0.0.4}/tests/universal/property_universal/__init__.py +0 -0
  182. {nab_python-0.0.3 → nab_python-0.0.4}/tests/universal/property_universal/strategies.py +0 -0
  183. {nab_python-0.0.3 → nab_python-0.0.4}/tests/universal/property_universal/test_alignment.py +0 -0
  184. {nab_python-0.0.3 → nab_python-0.0.4}/tests/universal/property_universal/test_matrix.py +0 -0
  185. {nab_python-0.0.3 → nab_python-0.0.4}/tests/universal/property_universal/test_validate.py +0 -0
  186. {nab_python-0.0.3 → nab_python-0.0.4}/tests/universal/test_reresolve.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nab-python
3
- Version: 0.0.3
3
+ Version: 0.0.4
4
4
  Summary: Index-backed provider, lockfile emitter, and downloader for nab
5
5
  Project-URL: Homepage, https://github.com/notatallshaw/nab
6
6
  Project-URL: Documentation, https://nab.readthedocs.io/
@@ -20,8 +20,8 @@ Classifier: Typing :: Typed
20
20
  Requires-Python: >=3.10
21
21
  Requires-Dist: build>=1.2
22
22
  Requires-Dist: installer>=0.7
23
- Requires-Dist: nab-index==0.0.3
24
- Requires-Dist: nab-resolver==0.0.3
23
+ Requires-Dist: nab-index==0.0.4
24
+ Requires-Dist: nab-resolver==0.0.4
25
25
  Requires-Dist: pyproject-hooks>=1.2
26
26
  Requires-Dist: tomli-w>=1.2
27
27
  Requires-Dist: tomli>=2.0
@@ -0,0 +1,139 @@
1
+ r"""Single-scenario profiling runner.
2
+
3
+ Usage:
4
+ # sampling profiler (requires .venv-3.15)
5
+ .venv-3.15/bin/python -m profiling.sampling run -r 5khz --flamegraph \
6
+ -o profile.html nab-python/benchmarks/_profile_runner.py <scenario>
7
+
8
+ # cProfile (any venv)
9
+ python nab-python/benchmarks/_profile_runner.py <scenario> --cprofile
10
+
11
+ <scenario> is a bare name (first TOML match wins) or ``toml_stem:name``,
12
+ e.g. ``pip-lowest:cburroughs-v3``.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import argparse
18
+ import cProfile
19
+ import pstats
20
+ import sys
21
+ from pathlib import Path
22
+
23
+ if sys.version_info >= (3, 11):
24
+ import tomllib
25
+ else:
26
+ import tomli as tomllib # type: ignore[no-redef]
27
+
28
+ sys.path.insert(0, str(Path(__file__).parent))
29
+
30
+ import scenarios as sc
31
+
32
+
33
+ def find_scenario(spec: str) -> tuple[str, dict]:
34
+ if ":" in spec:
35
+ toml_stem, name = spec.split(":", 1)
36
+ toml_path = sc.SCENARIOS_DIR / f"{toml_stem}.toml"
37
+ try:
38
+ with toml_path.open("rb") as f:
39
+ data = tomllib.load(f)
40
+ except FileNotFoundError:
41
+ sys.exit(f"no TOML file for stem {toml_stem!r}")
42
+ if name not in data:
43
+ sys.exit(f"scenario {name!r} not found in {toml_stem}.toml")
44
+ return name, data[name]
45
+ for path in sorted(sc.SCENARIOS_DIR.glob("*.toml")):
46
+ with path.open("rb") as f:
47
+ data = tomllib.load(f)
48
+ if spec in data:
49
+ return spec, data[spec]
50
+ sys.exit(f"scenario {spec!r} not found")
51
+
52
+
53
+ def build_inputs(name: str, scenario: dict) -> dict:
54
+ python_version = scenario["python_version"]
55
+ requirement_strings = list(scenario["requirements"])
56
+ constraint_strings = scenario.get("constraints", [])
57
+ marker_environment = sc.parse_marker_environment(name, scenario)
58
+ build_policy_overrides = sc.parse_build_packages(name, scenario)
59
+
60
+ # BUILD_REMOTE + marker_environment overlay is unsupported; drop overrides.
61
+ if marker_environment and build_policy_overrides:
62
+ build_policy_overrides = {}
63
+
64
+ resolution_strategy = sc.ResolutionStrategy(scenario.get("resolution", "highest"))
65
+ vcs_config = sc.VcsConfig(
66
+ policy=sc.VcsPolicy(scenario.get("vcs_policy", "block")),
67
+ allowed_schemes=frozenset(scenario.get("vcs_allowed_schemes", [])),
68
+ allowed_repos=tuple(scenario.get("vcs_allowed_repos", [])),
69
+ require_pin=scenario.get("vcs_require_pin", True),
70
+ )
71
+
72
+ if scenario.get("project_name"):
73
+ requirement_strings += sc.expand_project_extras(
74
+ scenario["project_name"],
75
+ scenario.get("project_extras", []),
76
+ scenario.get("optional_dependencies", {}),
77
+ )
78
+
79
+ marker_env = sc.scenario_marker_env(python_version, marker_environment)
80
+ requirements = sc.parse_requirements(
81
+ requirement_strings, vcs_config=vcs_config, marker_environment=marker_env
82
+ )
83
+ constraints = (
84
+ sc.parse_requirements(
85
+ constraint_strings, vcs_config=vcs_config, marker_environment=marker_env
86
+ )
87
+ if constraint_strings
88
+ else None
89
+ )
90
+
91
+ datetime_str = scenario.get("datetime")
92
+ return {
93
+ "requirements": requirements,
94
+ "python_version": python_version,
95
+ "uploaded_prior_to": sc.parse_datetime(datetime_str) if datetime_str else None,
96
+ "constraints": constraints,
97
+ "marker_environment": marker_environment or None,
98
+ "indexes": sc.parse_indexes(name, scenario),
99
+ "index_overrides": sc.parse_index_overrides(name, scenario) or None,
100
+ "build_policy_overrides": build_policy_overrides or None,
101
+ "resolution_strategy": resolution_strategy,
102
+ }
103
+
104
+
105
+ def report(name: str, data: dict) -> None:
106
+ stats = data["stats"]
107
+ state = "OK" if data["result"]["success"] else f"FAIL {data['result']['error']}"
108
+ print(
109
+ f"{name}: {state} in {stats['wall_time_seconds']}s, "
110
+ f"{stats['decisions']} decisions, {stats['conflicts']} conflicts"
111
+ )
112
+
113
+
114
+ def main() -> None:
115
+ parser = argparse.ArgumentParser(description=__doc__)
116
+ parser.add_argument("scenario", help="bare name or toml_stem:name")
117
+ parser.add_argument(
118
+ "--cprofile",
119
+ action="store_true",
120
+ help="profile in-process and print the top functions by self time",
121
+ )
122
+ parser.add_argument("--limit", type=int, default=30)
123
+ args = parser.parse_args()
124
+
125
+ name, scenario = find_scenario(args.scenario)
126
+ inputs = build_inputs(name, scenario)
127
+
128
+ if not args.cprofile:
129
+ report(name, sc.resolve_scenario(**inputs))
130
+ return
131
+
132
+ profiler = cProfile.Profile()
133
+ data = profiler.runcall(sc.resolve_scenario, **inputs)
134
+ report(name, data)
135
+ pstats.Stats(profiler).sort_stats("tottime").print_stats(args.limit)
136
+
137
+
138
+ if __name__ == "__main__":
139
+ main()
@@ -88,8 +88,12 @@ WALL_TIMEOUT_S = 60
88
88
  MAX_ITERATIONS = 50_000
89
89
 
90
90
 
91
- class _ScenarioTimeoutError(Exception):
92
- pass
91
+ class _ScenarioTimeoutError(BaseException):
92
+ """Raised when a scenario exceeds the per-run wall-clock budget.
93
+
94
+ Subclasses BaseException so the resolver's internal ``except Exception``
95
+ handlers cannot swallow the alarm mid-resolve.
96
+ """
93
97
 
94
98
 
95
99
  def _alarm_handler(_signum: int, _frame: object) -> None:
@@ -197,7 +201,7 @@ def get_git_commit() -> str:
197
201
  return result.stdout.strip()
198
202
 
199
203
 
200
- def run_one(
204
+ def run_one( # noqa: PLR0913 - one wrapper per scenario knob
201
205
  requirements: dict[str, VersionRange],
202
206
  python_version: str,
203
207
  uploaded_prior_to: datetime | None,
@@ -206,6 +210,8 @@ def run_one(
206
210
  indexes: list[IndexConfig] | None = None,
207
211
  index_overrides: list[IndexOverride] | None = None,
208
212
  build_policy_overrides: Mapping[str, BuildPolicy] | None = None,
213
+ *,
214
+ trust_unverified_sdist_deps: bool = False,
209
215
  ) -> dict:
210
216
  with FetchCoordinator(
211
217
  HttpxAsyncTransport(),
@@ -222,6 +228,7 @@ def run_one(
222
228
  dist_policy=DistPolicy.WHEEL_OR_SDIST,
223
229
  build_policy=BuildPolicy.NEVER,
224
230
  build_policy_overrides=build_policy_overrides,
231
+ trust_unverified_sdist_deps=trust_unverified_sdist_deps,
225
232
  marker_environment=marker_environment,
226
233
  )
227
234
  resolver = Resolver(
@@ -241,7 +248,7 @@ def run_one(
241
248
  success = True
242
249
  error = None
243
250
  packages = len(result)
244
- except Exception as exc:
251
+ except (_ScenarioTimeoutError, Exception) as exc:
245
252
  elapsed = time.monotonic() - start
246
253
  success = False
247
254
  error = f"{type(exc).__name__}: {exc}"
@@ -361,6 +368,9 @@ def median_run(scenario: dict, runs: int) -> tuple[list[dict], dict]:
361
368
  else None
362
369
  )
363
370
  uploaded_prior_to = parse_datetime(datetime_str) if datetime_str else None
371
+ trust_unverified_sdist_deps = bool(
372
+ scenario.get("trust_unverified_sdist_deps", False)
373
+ )
364
374
 
365
375
  runs_data: list[dict] = [
366
376
  run_one(
@@ -372,6 +382,7 @@ def median_run(scenario: dict, runs: int) -> tuple[list[dict], dict]:
372
382
  indexes=indexes,
373
383
  index_overrides=index_overrides or None,
374
384
  build_policy_overrides=build_policy_overrides or None,
385
+ trust_unverified_sdist_deps=trust_unverified_sdist_deps,
375
386
  )
376
387
  for _ in range(runs)
377
388
  ]
@@ -395,7 +395,7 @@ requirements = [
395
395
  resolution = "lowest-direct"
396
396
  python_version = "3.11"
397
397
  platform_system = "Linux"
398
- datetime = "2025-08-04 12:00:00"
398
+ datetime = "2025-08-05 20:00:00"
399
399
  requirements = [
400
400
  "openai==1.99.1",
401
401
  "llama-index~=0.12.52",
@@ -473,7 +473,7 @@ requirements = ["llama-index-readers-docling"]
473
473
  resolution = "lowest-direct"
474
474
  python_version = "3.11"
475
475
  platform_system = "Linux"
476
- datetime = "2025-08-13 06:32:08"
476
+ datetime = "2025-08-13 22:00:00"
477
477
  requirements = [
478
478
  "llama-index-embeddings-openai-like==0.2.1",
479
479
  "llama-index-core>=0.12.0",
@@ -565,6 +565,9 @@ resolution = "lowest-direct"
565
565
  python_version = "3.11"
566
566
  platform_system = "Linux"
567
567
  datetime = "2025-06-01 10:00:00"
568
+ # Resolves only by trusting a pre-2.2 sdist's PKG-INFO deps, which the
569
+ # strict PEP 643 default routes to a build (BuildPolicy.NEVER fails).
570
+ trust_unverified_sdist_deps = true
568
571
  requirements = [
569
572
  "streamlit",
570
573
  "langchain",
@@ -586,6 +589,9 @@ resolution = "lowest-direct"
586
589
  python_version = "3.10"
587
590
  platform_system = "Linux"
588
591
  datetime = "2025-01-16 13:37:05"
592
+ # Resolves only by trusting a pre-2.2 sdist's PKG-INFO deps, which the
593
+ # strict PEP 643 default routes to a build (BuildPolicy.NEVER fails).
594
+ trust_unverified_sdist_deps = true
589
595
  requirements = [
590
596
  "langchain",
591
597
  "langchain-community",
@@ -395,7 +395,7 @@ requirements = [
395
395
  resolution = "lowest"
396
396
  python_version = "3.11"
397
397
  platform_system = "Linux"
398
- datetime = "2025-08-04 12:00:00"
398
+ datetime = "2025-08-05 20:00:00"
399
399
  requirements = [
400
400
  "openai==1.99.1",
401
401
  "llama-index~=0.12.52",
@@ -473,7 +473,7 @@ requirements = ["llama-index-readers-docling"]
473
473
  resolution = "lowest"
474
474
  python_version = "3.11"
475
475
  platform_system = "Linux"
476
- datetime = "2025-08-13 06:32:08"
476
+ datetime = "2025-08-13 22:00:00"
477
477
  requirements = [
478
478
  "llama-index-embeddings-openai-like==0.2.1",
479
479
  "llama-index-core>=0.12.0",
@@ -565,6 +565,9 @@ resolution = "lowest"
565
565
  python_version = "3.11"
566
566
  platform_system = "Linux"
567
567
  datetime = "2025-06-01 10:00:00"
568
+ # Resolves only by trusting a pre-2.2 sdist's PKG-INFO deps, which the
569
+ # strict PEP 643 default routes to a build (BuildPolicy.NEVER fails).
570
+ trust_unverified_sdist_deps = true
568
571
  requirements = [
569
572
  "streamlit",
570
573
  "langchain",
@@ -586,6 +589,9 @@ resolution = "lowest"
586
589
  python_version = "3.10"
587
590
  platform_system = "Linux"
588
591
  datetime = "2025-01-16 13:37:05"
592
+ # Resolves only by trusting a pre-2.2 sdist's PKG-INFO deps, which the
593
+ # strict PEP 643 default routes to a build (BuildPolicy.NEVER fails).
594
+ trust_unverified_sdist_deps = true
589
595
  requirements = [
590
596
  "langchain",
591
597
  "langchain-community",
@@ -373,7 +373,7 @@ requirements = [
373
373
  # Same requirements, earlier PyPI snapshot.
374
374
  python_version = "3.11"
375
375
  platform_system = "Linux"
376
- datetime = "2025-08-04 12:00:00"
376
+ datetime = "2025-08-05 20:00:00"
377
377
  requirements = [
378
378
  "openai==1.99.1",
379
379
  "llama-index~=0.12.52",
@@ -445,7 +445,7 @@ requirements = ["llama-index-readers-docling"]
445
445
  # https://github.com/run-llama/llama_index/issues/19659
446
446
  python_version = "3.11"
447
447
  platform_system = "Linux"
448
- datetime = "2025-08-13 06:32:08"
448
+ datetime = "2025-08-13 22:00:00"
449
449
  requirements = [
450
450
  "llama-index-embeddings-openai-like==0.2.1",
451
451
  "llama-index-core>=0.12.0",
@@ -530,6 +530,9 @@ requirements = ["pyautogen[long-context]", "PyMuPDF"]
530
530
  python_version = "3.11"
531
531
  platform_system = "Linux"
532
532
  datetime = "2025-06-01 10:00:00"
533
+ # Resolves only by trusting a pre-2.2 sdist's PKG-INFO deps, which the
534
+ # strict PEP 643 default routes to a build (BuildPolicy.NEVER fails).
535
+ trust_unverified_sdist_deps = true
533
536
  requirements = [
534
537
  "streamlit",
535
538
  "langchain",
@@ -550,6 +553,9 @@ requirements = [
550
553
  python_version = "3.10"
551
554
  platform_system = "Linux"
552
555
  datetime = "2025-01-16 13:37:05"
556
+ # Resolves only by trusting a pre-2.2 sdist's PKG-INFO deps, which the
557
+ # strict PEP 643 default routes to a build (BuildPolicy.NEVER fails).
558
+ trust_unverified_sdist_deps = true
553
559
  requirements = [
554
560
  "langchain",
555
561
  "langchain-community",
@@ -215,42 +215,41 @@ requirements = [
215
215
  "kubernetes-asyncio",
216
216
  ]
217
217
 
218
- [airflow-october-regression-py310-full]
219
- # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356
220
- # Adds apache-airflow-core and apache-airflow-task-sdk co-pins to
221
- # airflow-october-regression (the CI run installs all three). Fails
222
- # on 3.10 / 3.11 / 3.13; succeeds on 3.12.
218
+ # apache-airflow 3.1.1 with the full provider-extra fan-out plus the
219
+ # apache-airflow-core and apache-airflow-task-sdk co-pins, from
220
+ # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356 (the CI run
221
+ # installs all three). pip's #13281 reports a per-Python split (ResolutionTooDeep
222
+ # on 3.10/3.11/3.13, only 3.12 resolves); nab resolves every Python, so it does
223
+ # not reproduce that regression. Heavy lowest-direct extras-fanout stress
224
+ # scenarios. The cutoff is 2025-11-01 because 3.1.1 was uploaded 2025-10-27.
225
+
226
+ [airflow-october-regression-py310]
223
227
  resolution = "lowest-direct"
224
228
  python_version = "3.10"
225
229
  platform_system = "Linux"
226
- datetime = "2025-10-13 23:19:02"
230
+ datetime = "2025-11-01 00:00:00"
227
231
  requirements = [
228
232
  "apache-airflow[aiobotocore,amazon,async,celery,cncf-kubernetes,common-io,common-messaging,docker,elasticsearch,fab,ftp,git,google,google-auth,graphviz,grpc,hashicorp,http,ldap,microsoft-azure,mysql,odbc,openlineage,pandas,postgres,redis,sendgrid,sftp,slack,snowflake,ssh,statsd,uv]==3.1.1",
229
233
  "apache-airflow-core==3.1.1",
230
234
  "apache-airflow-task-sdk==1.1.1",
231
235
  ]
232
236
 
233
- [airflow-october-regression-py313-full]
234
- # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356
235
- # Same as airflow-october-regression-py310-full on Python 3.13.
237
+ [airflow-october-regression-py312]
236
238
  resolution = "lowest-direct"
237
- python_version = "3.13"
239
+ python_version = "3.12"
238
240
  platform_system = "Linux"
239
- datetime = "2025-10-13 23:19:02"
241
+ datetime = "2025-11-01 00:00:00"
240
242
  requirements = [
241
243
  "apache-airflow[aiobotocore,amazon,async,celery,cncf-kubernetes,common-io,common-messaging,docker,elasticsearch,fab,ftp,git,google,google-auth,graphviz,grpc,hashicorp,http,ldap,microsoft-azure,mysql,odbc,openlineage,pandas,postgres,redis,sendgrid,sftp,slack,snowflake,ssh,statsd,uv]==3.1.1",
242
244
  "apache-airflow-core==3.1.1",
243
245
  "apache-airflow-task-sdk==1.1.1",
244
246
  ]
245
247
 
246
- [airflow-october-regression-py312-pass]
247
- # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356
248
- # 3.12 was reported as the only Python that resolves. Kept as a
249
- # passing baseline against airflow-october-regression-py310-full.
248
+ [airflow-october-regression-py313]
250
249
  resolution = "lowest-direct"
251
- python_version = "3.12"
250
+ python_version = "3.13"
252
251
  platform_system = "Linux"
253
- datetime = "2025-10-13 23:19:02"
252
+ datetime = "2025-11-01 00:00:00"
254
253
  requirements = [
255
254
  "apache-airflow[aiobotocore,amazon,async,celery,cncf-kubernetes,common-io,common-messaging,docker,elasticsearch,fab,ftp,git,google,google-auth,graphviz,grpc,hashicorp,http,ldap,microsoft-azure,mysql,odbc,openlineage,pandas,postgres,redis,sendgrid,sftp,slack,snowflake,ssh,statsd,uv]==3.1.1",
256
255
  "apache-airflow-core==3.1.1",
@@ -215,42 +215,39 @@ requirements = [
215
215
  "kubernetes-asyncio",
216
216
  ]
217
217
 
218
- [airflow-october-regression-py310-full]
219
- # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356
220
- # Adds apache-airflow-core and apache-airflow-task-sdk co-pins to
221
- # airflow-october-regression (the CI run installs all three). Fails
222
- # on 3.10 / 3.11 / 3.13; succeeds on 3.12.
218
+ # apache-airflow 3.1.1 with the full provider-extra fan-out plus
219
+ # apache-airflow-core and apache-airflow-task-sdk co-pins, from
220
+ # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356 (the CI run
221
+ # installs all three). pip's #13281 reports ResolutionTooDeep on 3.10/3.11/3.13;
222
+ # nab resolves every Python. Cutoff is 2025-11-01 (3.1.1 uploaded 2025-10-27).
223
+
224
+ [airflow-october-regression-py310]
223
225
  resolution = "lowest"
224
226
  python_version = "3.10"
225
227
  platform_system = "Linux"
226
- datetime = "2025-10-13 23:19:02"
228
+ datetime = "2025-11-01 00:00:00"
227
229
  requirements = [
228
230
  "apache-airflow[aiobotocore,amazon,async,celery,cncf-kubernetes,common-io,common-messaging,docker,elasticsearch,fab,ftp,git,google,google-auth,graphviz,grpc,hashicorp,http,ldap,microsoft-azure,mysql,odbc,openlineage,pandas,postgres,redis,sendgrid,sftp,slack,snowflake,ssh,statsd,uv]==3.1.1",
229
231
  "apache-airflow-core==3.1.1",
230
232
  "apache-airflow-task-sdk==1.1.1",
231
233
  ]
232
234
 
233
- [airflow-october-regression-py313-full]
234
- # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356
235
- # Same as airflow-october-regression-py310-full on Python 3.13.
235
+ [airflow-october-regression-py312]
236
236
  resolution = "lowest"
237
- python_version = "3.13"
237
+ python_version = "3.12"
238
238
  platform_system = "Linux"
239
- datetime = "2025-10-13 23:19:02"
239
+ datetime = "2025-11-01 00:00:00"
240
240
  requirements = [
241
241
  "apache-airflow[aiobotocore,amazon,async,celery,cncf-kubernetes,common-io,common-messaging,docker,elasticsearch,fab,ftp,git,google,google-auth,graphviz,grpc,hashicorp,http,ldap,microsoft-azure,mysql,odbc,openlineage,pandas,postgres,redis,sendgrid,sftp,slack,snowflake,ssh,statsd,uv]==3.1.1",
242
242
  "apache-airflow-core==3.1.1",
243
243
  "apache-airflow-task-sdk==1.1.1",
244
244
  ]
245
245
 
246
- [airflow-october-regression-py312-pass]
247
- # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356
248
- # 3.12 was reported as the only Python that resolves. Kept as a
249
- # passing baseline against airflow-october-regression-py310-full.
246
+ [airflow-october-regression-py313]
250
247
  resolution = "lowest"
251
- python_version = "3.12"
248
+ python_version = "3.13"
252
249
  platform_system = "Linux"
253
- datetime = "2025-10-13 23:19:02"
250
+ datetime = "2025-11-01 00:00:00"
254
251
  requirements = [
255
252
  "apache-airflow[aiobotocore,amazon,async,celery,cncf-kubernetes,common-io,common-messaging,docker,elasticsearch,fab,ftp,git,google,google-auth,graphviz,grpc,hashicorp,http,ldap,microsoft-azure,mysql,odbc,openlineage,pandas,postgres,redis,sendgrid,sftp,slack,snowflake,ssh,statsd,uv]==3.1.1",
256
253
  "apache-airflow-core==3.1.1",
@@ -197,39 +197,36 @@ requirements = [
197
197
  "kubernetes-asyncio",
198
198
  ]
199
199
 
200
- [airflow-october-regression-py310-full]
201
- # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356
202
- # Adds apache-airflow-core and apache-airflow-task-sdk co-pins to
203
- # airflow-october-regression (the CI run installs all three). Fails
204
- # on 3.10 / 3.11 / 3.13; succeeds on 3.12.
200
+ # apache-airflow 3.1.1 with the full provider-extra fan-out plus
201
+ # apache-airflow-core and apache-airflow-task-sdk co-pins, from
202
+ # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356 (the CI run
203
+ # installs all three). pip's #13281 reports ResolutionTooDeep on 3.10/3.11/3.13;
204
+ # nab resolves every Python. Cutoff is 2025-11-01 (3.1.1 uploaded 2025-10-27).
205
+
206
+ [airflow-october-regression-py310]
205
207
  python_version = "3.10"
206
208
  platform_system = "Linux"
207
- datetime = "2025-10-13 23:19:02"
209
+ datetime = "2025-11-01 00:00:00"
208
210
  requirements = [
209
211
  "apache-airflow[aiobotocore,amazon,async,celery,cncf-kubernetes,common-io,common-messaging,docker,elasticsearch,fab,ftp,git,google,google-auth,graphviz,grpc,hashicorp,http,ldap,microsoft-azure,mysql,odbc,openlineage,pandas,postgres,redis,sendgrid,sftp,slack,snowflake,ssh,statsd,uv]==3.1.1",
210
212
  "apache-airflow-core==3.1.1",
211
213
  "apache-airflow-task-sdk==1.1.1",
212
214
  ]
213
215
 
214
- [airflow-october-regression-py313-full]
215
- # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356
216
- # Same as airflow-october-regression-py310-full on Python 3.13.
217
- python_version = "3.13"
216
+ [airflow-october-regression-py312]
217
+ python_version = "3.12"
218
218
  platform_system = "Linux"
219
- datetime = "2025-10-13 23:19:02"
219
+ datetime = "2025-11-01 00:00:00"
220
220
  requirements = [
221
221
  "apache-airflow[aiobotocore,amazon,async,celery,cncf-kubernetes,common-io,common-messaging,docker,elasticsearch,fab,ftp,git,google,google-auth,graphviz,grpc,hashicorp,http,ldap,microsoft-azure,mysql,odbc,openlineage,pandas,postgres,redis,sendgrid,sftp,slack,snowflake,ssh,statsd,uv]==3.1.1",
222
222
  "apache-airflow-core==3.1.1",
223
223
  "apache-airflow-task-sdk==1.1.1",
224
224
  ]
225
225
 
226
- [airflow-october-regression-py312-pass]
227
- # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356
228
- # 3.12 was reported as the only Python that resolves. Kept as a
229
- # passing baseline against airflow-october-regression-py310-full.
230
- python_version = "3.12"
226
+ [airflow-october-regression-py313]
227
+ python_version = "3.13"
231
228
  platform_system = "Linux"
232
- datetime = "2025-10-13 23:19:02"
229
+ datetime = "2025-11-01 00:00:00"
233
230
  requirements = [
234
231
  "apache-airflow[aiobotocore,amazon,async,celery,cncf-kubernetes,common-io,common-messaging,docker,elasticsearch,fab,ftp,git,google,google-auth,graphviz,grpc,hashicorp,http,ldap,microsoft-azure,mysql,odbc,openlineage,pandas,postgres,redis,sendgrid,sftp,slack,snowflake,ssh,statsd,uv]==3.1.1",
235
232
  "apache-airflow-core==3.1.1",
@@ -699,12 +699,15 @@ requirements = [
699
699
  ]
700
700
 
701
701
  [airflow-october-regression]
702
- # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356
703
- # Airflow 3.1.1 from main: ResolutionTooDeep on 3.10 / 3.11 / 3.13 but not 3.12.
702
+ # apache-airflow 3.1.1 with the full provider-extra fan-out, from
703
+ # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356. pip's #13281
704
+ # reports ResolutionTooDeep on 3.10/3.11/3.13 (only 3.12 resolves); nab resolves
705
+ # py3.11, so it does not reproduce that regression. The cutoff is 2025-11-01
706
+ # because 3.1.1 was uploaded 2025-10-27.
704
707
  resolution = "lowest-direct"
705
708
  python_version = "3.11"
706
709
  platform_system = "Linux"
707
- datetime = "2025-10-13 23:19:02"
710
+ datetime = "2025-11-01 00:00:00"
708
711
  requirements = [
709
712
  "apache-airflow[aiobotocore,amazon,async,celery,cncf-kubernetes,common-io,common-messaging,docker,elasticsearch,fab,ftp,git,google,google-auth,graphviz,grpc,hashicorp,http,ldap,microsoft-azure,mysql,odbc,openlineage,pandas,postgres,redis,sendgrid,sftp,slack,snowflake,ssh,statsd,uv]==3.1.1",
710
713
  ]
@@ -699,12 +699,15 @@ requirements = [
699
699
  ]
700
700
 
701
701
  [airflow-october-regression]
702
- # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356
703
- # Airflow 3.1.1 from main: ResolutionTooDeep on 3.10 / 3.11 / 3.13 but not 3.12.
702
+ # apache-airflow 3.1.1 with the full provider-extra fan-out, from
703
+ # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356. pip's #13281
704
+ # reports ResolutionTooDeep on 3.10/3.11/3.13 (only 3.12 resolves); nab resolves
705
+ # py3.11, so it does not reproduce that regression. The cutoff is 2025-11-01
706
+ # because 3.1.1 was uploaded 2025-10-27.
704
707
  resolution = "lowest"
705
708
  python_version = "3.11"
706
709
  platform_system = "Linux"
707
- datetime = "2025-10-13 23:19:02"
710
+ datetime = "2025-11-01 00:00:00"
708
711
  requirements = [
709
712
  "apache-airflow[aiobotocore,amazon,async,celery,cncf-kubernetes,common-io,common-messaging,docker,elasticsearch,fab,ftp,git,google,google-auth,graphviz,grpc,hashicorp,http,ldap,microsoft-azure,mysql,odbc,openlineage,pandas,postgres,redis,sendgrid,sftp,slack,snowflake,ssh,statsd,uv]==3.1.1",
710
713
  ]
@@ -663,11 +663,14 @@ requirements = [
663
663
  ]
664
664
 
665
665
  [airflow-october-regression]
666
- # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356
667
- # Airflow 3.1.1 from main: ResolutionTooDeep on 3.10 / 3.11 / 3.13 but not 3.12.
666
+ # apache-airflow 3.1.1 with the full provider-extra fan-out, from
667
+ # https://github.com/pypa/pip/issues/13281#issuecomment-3399373356. pip's #13281
668
+ # reports ResolutionTooDeep on 3.10/3.11/3.13 (only 3.12 resolves); nab resolves
669
+ # py3.11, so it does not reproduce that regression. The cutoff is 2025-11-01
670
+ # because 3.1.1 was uploaded 2025-10-27.
668
671
  python_version = "3.11"
669
672
  platform_system = "Linux"
670
- datetime = "2025-10-13 23:19:02"
673
+ datetime = "2025-11-01 00:00:00"
671
674
  requirements = [
672
675
  "apache-airflow[aiobotocore,amazon,async,celery,cncf-kubernetes,common-io,common-messaging,docker,elasticsearch,fab,ftp,git,google,google-auth,graphviz,grpc,hashicorp,http,ldap,microsoft-azure,mysql,odbc,openlineage,pandas,postgres,redis,sendgrid,sftp,slack,snowflake,ssh,statsd,uv]==3.1.1",
673
676
  ]
@@ -333,3 +333,19 @@ platforms = ["linux_x86_64"]
333
333
  requirements = ["apache-airflow-providers-amazon", "numpy"]
334
334
  datetime = "2024-09-01 00:00:00"
335
335
  align_across_tuples = true
336
+
337
+ [numpy-wide-python-diverge]
338
+ reason = "py-minor version-floor divergence; tests matrix divergence path"
339
+ python = ">=3.9, <3.14"
340
+ platforms = ["linux_x86_64"]
341
+ requirements = ["numpy", "scipy", "pandas"]
342
+ datetime = "2025-06-01 00:00:00"
343
+ align_across_tuples = false
344
+
345
+ [numpy-wide-python-align]
346
+ reason = "same as numpy-wide-python-diverge with alignment; measures alignment cost"
347
+ python = ">=3.9, <3.14"
348
+ platforms = ["linux_x86_64"]
349
+ requirements = ["numpy", "scipy", "pandas"]
350
+ datetime = "2025-06-01 00:00:00"
351
+ align_across_tuples = true