LbAPLocal 0.9.3__tar.gz → 0.9.5__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 (139) hide show
  1. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/PKG-INFO +1 -1
  2. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal/cli/main.py +58 -22
  3. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal/cli/wizards.py +2 -2
  4. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal/cwl/generate_replica_map.py +110 -76
  5. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal.egg-info/PKG-INFO +1 -1
  6. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/.coveragerc +0 -0
  7. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/.gitattributes +0 -0
  8. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/.gitignore +0 -0
  9. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/.gitlab-ci.yml +0 -0
  10. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/.pre-commit-config.yaml +0 -0
  11. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/CONTRIBUTING.md +0 -0
  12. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/LICENSE +0 -0
  13. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/README.md +0 -0
  14. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/example.json +0 -0
  15. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/pyproject.toml +0 -0
  16. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/setup.cfg +0 -0
  17. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal/__init__.py +0 -0
  18. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal/cli/__init__.py +0 -0
  19. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal/cli/legacy.py +0 -0
  20. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal/cli/textual_ui.py +0 -0
  21. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal/cwl/__init__.py +0 -0
  22. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal/cwl/rewrite.py +0 -0
  23. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal/job_slice.py +0 -0
  24. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal/log_parsing.py +0 -0
  25. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal/testing.py +0 -0
  26. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal/utils.py +0 -0
  27. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal.egg-info/SOURCES.txt +0 -0
  28. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal.egg-info/dependency_links.txt +0 -0
  29. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal.egg-info/entry_points.txt +0 -0
  30. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal.egg-info/requires.txt +0 -0
  31. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/src/LbAPLocal.egg-info/top_level.txt +0 -0
  32. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/capture_fixtures.py +0 -0
  33. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/cassettes/test_execute/test_run_test[2016_MagDown_PromptMC_D02KK-2444].yaml +0 -0
  34. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/cassettes/test_execute/test_run_test[2016_MagDown_PromptMC_D02KK_noautoconf-2444].yaml +0 -0
  35. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/cassettes/test_execute/test_run_test[2016_MagUp_PromptMC_D02KK-2393].yaml +0 -0
  36. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/cassettes/test_execute/test_run_test[2016_MagUp_PromptMC_D02KK_noautoconf-2393].yaml +0 -0
  37. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/conftest.py +0 -0
  38. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/.gitignore +0 -0
  39. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/.gitlab-ci.yml +0 -0
  40. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/AnalysisProductions.xenv +0 -0
  41. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/Bc2Bspi2JpsiPhi.py +0 -0
  42. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/Bd2JpsiKstar.py +0 -0
  43. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/Bd2JpsiKstar_stripping.py +0 -0
  44. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/Bs2DsPi.py +0 -0
  45. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/Bs2JpsiPhi.py +0 -0
  46. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/Bs2JpsiPhi_Prompt.py +0 -0
  47. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/Bs2JpsiPhi_Prompt_PVMixer.py +0 -0
  48. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/Bs2JpsiPhi_Swave.py +0 -0
  49. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/Bu2JpsiKplus.py +0 -0
  50. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/Bu2JpsiKplus_stripping.py +0 -0
  51. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/LbJpsipK.py +0 -0
  52. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/README.md +0 -0
  53. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/helpers/__init__.py +0 -0
  54. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/helpers/stripping.py +0 -0
  55. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/helpers/tuple_maker.py +0 -0
  56. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/info.yaml +0 -0
  57. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/BsToJpsiPhi/sequence_setup.py +0 -0
  58. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/COPYING +0 -0
  59. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/RDs/README.md +0 -0
  60. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/RDs/Run1_Signal.py +0 -0
  61. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/RDs/Run2_Signal.py +0 -0
  62. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/RDs/helpers/__init__.py +0 -0
  63. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/RDs/helpers/signal_tuple_maker.py +0 -0
  64. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/RDs/info.yaml +0 -0
  65. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/README.md +0 -0
  66. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/__init__.py +0 -0
  67. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/2011_datatype.py +0 -0
  68. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/2012_datatype.py +0 -0
  69. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/2015_datatype.py +0 -0
  70. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/2016_datatype.py +0 -0
  71. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/2017_datatype.py +0 -0
  72. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/2018_datatype.py +0 -0
  73. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/B0ToK0ee.py +0 -0
  74. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/B0ToK0mumu.py +0 -0
  75. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/BpToKee.py +0 -0
  76. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/BpToKmumu.py +0 -0
  77. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/LbToL0ee.py +0 -0
  78. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/LbToL0eeSS.py +0 -0
  79. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/LbToL0emu.py +0 -0
  80. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/LbToL0emuSS.py +0 -0
  81. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/LbToL0mumu.py +0 -0
  82. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/LbToL0mumuSS.py +0 -0
  83. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/README.md +0 -0
  84. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/__init__.py +0 -0
  85. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/general_options.py +0 -0
  86. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/helpers/MC_tuple_maker.py +0 -0
  87. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/helpers/__init__.py +0 -0
  88. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/helpers/decay_descriptors.py +0 -0
  89. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/helpers/locations.py +0 -0
  90. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/helpers/related_info.py +0 -0
  91. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/helpers/stripping.py +0 -0
  92. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/helpers/tags.py +0 -0
  93. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/helpers/tuple_maker.py +0 -0
  94. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/info.yaml +0 -0
  95. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_general_options_DST.py +0 -0
  96. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_general_options_FDST.py +0 -0
  97. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_general_options_FMDST.py +0 -0
  98. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_general_options_MDST.py +0 -0
  99. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Bd2JpsiKs_ee.py +0 -0
  100. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Bd2JpsiKs_mm.py +0 -0
  101. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Bd2Ksee.py +0 -0
  102. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Bd2Ksmm.py +0 -0
  103. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Bd2PsiKs_ee.py +0 -0
  104. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Bd2PsiKs_mm.py +0 -0
  105. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Bu2JpsiK_ee.py +0 -0
  106. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Bu2JpsiK_mm.py +0 -0
  107. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Lb2JpsiL_ee.py +0 -0
  108. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Lb2JpsiL_mm.py +0 -0
  109. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Lb2Lee.py +0 -0
  110. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Lb2Lem.py +0 -0
  111. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Lb2Lmm.py +0 -0
  112. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Lb2PsiL_ee.py +0 -0
  113. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/mc_samples/MC_Lb2PsiL_mm.py +0 -0
  114. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/sequence_setup.py +0 -0
  115. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/cbtesting/stripping_seq.py +0 -0
  116. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/executabletests/2016_MagDown_PromptMC_D02KK_autoconf.py +0 -0
  117. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/executabletests/2016_MagUp_PromptMC_D02KK_autoconf.py +0 -0
  118. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/executabletests/info.yaml +0 -0
  119. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/data-pkg-repo/executabletests/ntuple_options.py +0 -0
  120. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/example-logs/error-failed-to-read-file.log +0 -0
  121. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/example-logs/error-illegal-instruction.log +0 -0
  122. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/example-logs/error-missing-shared-library.log +0 -0
  123. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/example-logs/error-platform-unsupported.log +0 -0
  124. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/example-logs/error-related-info-missing.log +0 -0
  125. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/example-logs/good-DaVinci_00110296_00000038_1.log +0 -0
  126. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/example-logs/good-DaVinci_00110296_00000194_1.log +0 -0
  127. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/data/example-logs/good-Gauss_00104988_00000011_1.log +0 -0
  128. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/fixture_loader.py +0 -0
  129. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/fixtures/executabletests/2016_MagDown_PromptMC_D02KK/query_result.json +0 -0
  130. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/fixtures/executabletests/2016_MagUp_PromptMC_D02KK/query_result.json +0 -0
  131. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/fixtures/executabletests/manifest.yaml +0 -0
  132. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/reslice_fixture.py +0 -0
  133. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/test-input-dst/00070767_00000711_7.AllStreams_slice.dst +0 -0
  134. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/test-input-dst/00070793_00000685_7.AllStreams_slice.dst +0 -0
  135. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/test_cli.py +0 -0
  136. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/test_cwl_cli.py +0 -0
  137. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/test_execute.py +0 -0
  138. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/test_local_datapkg.py +0 -0
  139. {lbaplocal-0.9.3 → lbaplocal-0.9.5}/tests/test_log_parse.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: LbAPLocal
3
- Version: 0.9.3
3
+ Version: 0.9.5
4
4
  Summary: Tool to locally run tests for AnalysisProductions
5
5
  Author: LHCb
6
6
  Project-URL: Homepage, https://gitlab.cern.ch/lhcb-dpa/analysis-productions/lbaplocal
@@ -115,13 +115,13 @@ _TIPS = [
115
115
  "Use [bold cyan]lb-ap test --pretty[/] for a split-view of real-time logs",
116
116
  "Use [bold cyan]lb-ap list --tree[/] for a tree view of productions and jobs",
117
117
  "Use [bold cyan]lb-ap test --dry-run[/] to validate config without running",
118
- "Use [bold cyan]lb-ap test --pick-smallest-lfn[/] for faster testing with small files",
119
- "Use [bold cyan]lb-ap clone[/] with no args for an interactive wizard",
118
+ "Use [bold cyan]lb-ap clone[/] to quickly clone a repository with the right branch or tag",
120
119
  "Use [bold cyan]lb-ap -b my-branch test ...[/] to auto-clone and test a branch",
121
120
  "Use [bold cyan]lb-ap test -i local.dst ...[/] to test with a local input file",
121
+ "Use [bold cyan]lb-ap test -i LFN:/lhcb/.../gridfile.dst ...[/] to test with a file on the grid",
122
122
  "Use [bold cyan]lb-ap make-reproducer -s single-event[/] for the smallest tarball",
123
123
  "Use [bold cyan]lb-ap -C /path/to/repo list[/] to run from a different directory",
124
- "Use [bold cyan]lb-ap test --n-lfns 5 --pick-smallest-lfn[/] to test with multiple small files",
124
+ "Use [bold cyan]lb-ap test --n-lfns 1 --pick-smallest-lfn[/] to test with the smallest file available",
125
125
  "Use [bold cyan]lb-ap checkout -w[/] for an interactive checkout wizard",
126
126
  "Use [bold cyan]lb-ap versions[/] to list available production versions",
127
127
  "Clones are cached in [dim]~/.cache/lbaplocal/clones/[/] for reuse",
@@ -460,11 +460,11 @@ def main(
460
460
  rich formatting, better error messages, and CWL workflow integration.
461
461
 
462
462
  Use -C to run commands from a different directory:
463
- lb-ap-exp -C /path/to/AnalysisProductions list
463
+ lb-ap -C /path/to/AnalysisProductions list
464
464
 
465
465
  Use --branch to auto-clone or checkout a branch:
466
- lb-ap-exp --branch my-feature list
467
- lb-ap-exp -C /path/to/repo --branch my-feature test MyJob
466
+ lb-ap --branch my-feature list
467
+ lb-ap -C /path/to/repo --branch my-feature test MyJob
468
468
  """
469
469
  # Determine version string
470
470
  try:
@@ -1025,21 +1025,21 @@ def versions(
1025
1025
  working group and production name.
1026
1026
 
1027
1027
  Examples:
1028
- lb-ap-exp versions
1029
- lb-ap-exp versions charm MyAnalysis
1028
+ lb-ap versions
1029
+ lb-ap versions charm MyAnalysis
1030
1030
  """
1031
1031
  if not production_name and not working_group:
1032
1032
  err_console.print(
1033
1033
  "[bold yellow]⚠ Version querying currently requires both working group "
1034
1034
  "and production name[/bold yellow]\n"
1035
- "Usage: [cyan]lb-ap-exp versions WORKING_GROUP PRODUCTION_NAME[/cyan]"
1035
+ "Usage: [cyan]lb-ap versions WORKING_GROUP PRODUCTION_NAME[/cyan]"
1036
1036
  )
1037
1037
  raise typer.Exit(code=1)
1038
1038
 
1039
1039
  if working_group and not production_name:
1040
1040
  err_console.print(
1041
1041
  "[bold yellow]⚠ Please specify both working group and production name[/bold yellow]\n"
1042
- "Usage: [cyan]lb-ap-exp versions WORKING_GROUP PRODUCTION_NAME[/cyan]"
1042
+ "Usage: [cyan]lb-ap versions WORKING_GROUP PRODUCTION_NAME[/cyan]"
1043
1043
  )
1044
1044
  raise typer.Exit(code=1)
1045
1045
 
@@ -1114,19 +1114,19 @@ def clone(
1114
1114
 
1115
1115
  **Branch Mode** (1 argument):
1116
1116
  Clone and checkout/create a branch for general development
1117
- Example: lb-ap-exp clone my-feature-branch
1117
+ Example: lb-ap clone my-feature-branch
1118
1118
 
1119
1119
  **Production Mode** (4 arguments):
1120
1120
  Clone and checkout a specific production version to a NEW branch
1121
- Example: lb-ap-exp clone charm MyAnalysis v1.0 my-new-branch
1121
+ Example: lb-ap clone charm MyAnalysis v1.0 my-new-branch
1122
1122
 
1123
1123
  If no arguments: Interactive wizard
1124
1124
 
1125
1125
  Examples:
1126
- lb-ap-exp clone # Interactive wizard
1127
- lb-ap-exp clone master # Branch mode: checkout master
1128
- lb-ap-exp clone my-feature # Branch mode: create 'my-feature'
1129
- lb-ap-exp clone charm MyAnalysis v1.0 work-branch # Production mode
1126
+ lb-ap clone # Interactive wizard
1127
+ lb-ap clone master # Branch mode: checkout master
1128
+ lb-ap clone my-feature # Branch mode: create 'my-feature'
1129
+ lb-ap clone charm MyAnalysis v1.0 work-branch # Production mode
1130
1130
  """
1131
1131
  # Auto-detect clone type if not specified
1132
1132
  if clone_type is None:
@@ -1352,9 +1352,9 @@ def checkout(
1352
1352
  If arguments are omitted, an interactive wizard will guide you through the process.
1353
1353
 
1354
1354
  Examples:
1355
- lb-ap-exp checkout # Interactive wizard
1356
- lb-ap-exp checkout charm MyAnalysis v1.0 my-branch
1357
- lb-ap-exp checkout beauty Analysis v2.1 test --allow-deletes
1355
+ lb-ap checkout # Interactive wizard
1356
+ lb-ap checkout charm MyAnalysis v1.0 my-branch
1357
+ lb-ap checkout beauty Analysis v2.1 test --allow-deletes
1358
1358
  """
1359
1359
  # Use wizard if arguments missing or interactive mode requested
1360
1360
  if interactive or not all([working_group, production_name, version, branch_name]):
@@ -1404,9 +1404,9 @@ def list_productions(
1404
1404
  List all available production folders, or jobs within a specific production.
1405
1405
 
1406
1406
  Examples:
1407
- lb-ap-exp list
1408
- lb-ap-exp list MyAnalysis
1409
- lb-ap-exp list MyAnalysis --tree
1407
+ lb-ap list
1408
+ lb-ap list MyAnalysis
1409
+ lb-ap list MyAnalysis --tree
1410
1410
  """
1411
1411
  try:
1412
1412
  inside_ap_datapkg()
@@ -3387,6 +3387,7 @@ def cwl_test(
3387
3387
 
3388
3388
  # Step 2b: Rewrite CWL for custom input (if provided)
3389
3389
  cwl_inputs_path = None
3390
+ replica_map_path = None
3390
3391
  if dependent_input:
3391
3392
  from LbAPLocal.cwl.rewrite import rewrite_cwl_for_custom_input
3392
3393
 
@@ -3408,6 +3409,39 @@ def cwl_test(
3408
3409
  err_console.print(traceback.format_exc())
3409
3410
  raise typer.Exit(code=1)
3410
3411
 
3412
+ # Generate replica map for LFN custom inputs so the executor can resolve them
3413
+ if dependent_input.startswith("LFN:"):
3414
+ console.print(
3415
+ "\n[bold cyan]Generating replica map for custom input LFN[/bold cyan]"
3416
+ )
3417
+ import importlib.util
3418
+
3419
+ spec = importlib.util.find_spec("LbAPLocal.cwl.generate_replica_map")
3420
+ if spec is None or spec.origin is None:
3421
+ err_console.print(
3422
+ "[bold red]✗ Could not find LbAPLocal.cwl.generate_replica_map module[/bold red]"
3423
+ )
3424
+ raise typer.Exit(code=1)
3425
+
3426
+ map_path = output_dir / f"{cwl_workflow_path.stem}-replica-map.json"
3427
+ cmd_map = [
3428
+ "lb-dirac",
3429
+ "python",
3430
+ spec.origin,
3431
+ "--lfns",
3432
+ dependent_input,
3433
+ "--output-map",
3434
+ str(map_path),
3435
+ ]
3436
+ result = subprocess.run(cmd_map, capture_output=True, text=True)
3437
+ if result.returncode != 0:
3438
+ err_console.print(
3439
+ f"[bold red]✗ Failed to generate replica map:[/bold red]\n{result.stderr}"
3440
+ )
3441
+ raise typer.Exit(code=1)
3442
+ replica_map_path = map_path
3443
+ console.print(f"[green]✓ Generated replica map:[/green] {replica_map_path}")
3444
+
3411
3445
  # Step 3: Execute CWL workflow
3412
3446
  console.print("\n[bold cyan]Step 3/3: Executing CWL workflow[/bold cyan]")
3413
3447
 
@@ -3511,6 +3545,8 @@ def cwl_test(
3511
3545
  cmd.append("--verbose")
3512
3546
  cmd.extend(["--preserve-environment", "CMAKE_PREFIX_PATH"])
3513
3547
  cmd.extend(["--preserve-environment", "ANALYSIS_PRODUCTIONS_DYNAMIC"])
3548
+ if replica_map_path:
3549
+ cmd.extend(["--replica-map", str(replica_map_path)])
3514
3550
 
3515
3551
  # Add workflow file
3516
3552
  cmd.append(str(cwl_workflow_path.resolve()))
@@ -106,7 +106,7 @@ def clone_wizard() -> dict:
106
106
  )
107
107
 
108
108
  console.print("\n[bold cyan]Step 3:[/bold cyan] Version")
109
- console.print("[dim]Tip: Use 'lb-ap-exp versions' to see available versions[/dim]")
109
+ console.print("[dim]Tip: Use 'lb-ap versions' to see available versions[/dim]")
110
110
  version = Prompt.ask(
111
111
  "Enter version tag",
112
112
  default="master",
@@ -286,7 +286,7 @@ def test_wizard(productions: Optional[List[str]] = None) -> dict:
286
286
  job_name = Prompt.ask("Enter job name")
287
287
  else:
288
288
  console.print(
289
- "[dim]Tip: Use 'lb-ap-exp list <production>' to see available jobs[/dim]"
289
+ "[dim]Tip: Use 'lb-ap list <production>' to see available jobs[/dim]"
290
290
  )
291
291
  job_name = Prompt.ask("Enter job name")
292
292
  except Exception as e:
@@ -439,7 +439,7 @@ def do_bkquery(
439
439
  for record in records:
440
440
  lfn = record[filenameIndex]
441
441
  replica_result = returnValueOrRaise(
442
- DataManager().getReplicasForJobs([lfn], diskOnly=True)
442
+ DataManager().getReplicasForJobs([lfn], diskOnly=True, protocol="root")
443
443
  )
444
444
  inputFiles.extend(replica_result["Successful"])
445
445
  if len(inputFiles) == numTestLFNs:
@@ -495,12 +495,10 @@ app = typer.Typer(
495
495
 
496
496
  @app.command()
497
497
  def main(
498
- cwl_file: Path = typer.Argument(
499
- ...,
500
- help="Path to CWL file with dirac:Production hint",
501
- exists=True,
498
+ cwl_file: Path | None = typer.Argument(
499
+ None,
500
+ help="Path to CWL file with dirac:Production hint (not needed when --lfns is provided)",
502
501
  dir_okay=False,
503
- readable=True,
504
502
  ),
505
503
  n_lfns: int | None = typer.Option(
506
504
  None,
@@ -518,18 +516,23 @@ def main(
518
516
  "--download",
519
517
  help="Download input files locally instead of using remote protocol where available",
520
518
  ),
521
- output_yaml: Path = typer.Option(
519
+ output_yaml: Path | None = typer.Option(
522
520
  None,
523
521
  "--output-yaml",
524
522
  "-o",
525
523
  help="Output path for CWL input YAML file (default: <cwl_file>-inputs.yml)",
526
524
  ),
527
- output_map: Path = typer.Option(
525
+ output_map: Path | None = typer.Option(
528
526
  None,
529
527
  "--output-map",
530
528
  "-c",
531
529
  help="Output path for replica map JSON (default: <cwl_file>-replica-map.json)",
532
530
  ),
531
+ lfns: list[str] = typer.Option(
532
+ [],
533
+ "--lfns",
534
+ help="LFN paths to use directly, bypassing the Bookkeeping query (requires --output-map)",
535
+ ),
533
536
  verbose: bool = typer.Option(
534
537
  False,
535
538
  "--verbose",
@@ -544,15 +547,24 @@ def main(
544
547
 
545
548
  1. A CWL input YAML file with the input-data parameter
546
549
  2. A replica map JSON file for local execution
550
+
551
+ Alternatively, pass --lfns to skip the Bookkeeping query and generate a replica map
552
+ directly for specific LFNs (e.g. when using a custom input file).
547
553
  """
548
554
  if verbose:
549
555
  logger.setLevel(logging.DEBUG)
550
556
 
551
- # Validate flags
552
- if pick_smallest and n_lfns is None:
553
- console.print(
554
- "[red]Error:[/red] --pick-smallest-lfn requires --n-lfns to be specified"
555
- )
557
+ # Validate: require either cwl_file or --lfns
558
+ if not lfns and cwl_file is None:
559
+ console.print("[red]Error:[/red] Provide a CWL file or use --lfns")
560
+ raise typer.Exit(1)
561
+
562
+ if lfns and cwl_file is not None:
563
+ console.print("[red]Error:[/red] --lfns and a CWL file are mutually exclusive")
564
+ raise typer.Exit(1)
565
+
566
+ if cwl_file is not None and not cwl_file.exists():
567
+ console.print(f"[red]Error:[/red] CWL file not found: {cwl_file}")
556
568
  raise typer.Exit(1)
557
569
 
558
570
  # initialise dirac first
@@ -560,61 +572,83 @@ def main(
560
572
 
561
573
  DIRAC.initialize()
562
574
 
563
- # Set default output paths if not provided
564
- if output_yaml is None:
565
- output_yaml = cwl_file.parent / f"{cwl_file.stem}-inputs.yml"
566
- if output_map is None:
567
- output_map = cwl_file.parent / f"{cwl_file.stem}-replica-map.json"
568
-
569
- # Read the CWL file and extract inputDataset hint
570
- logger.info(f"Reading CWL file: {cwl_file}")
571
- with open(cwl_file, "r") as f:
572
- cwl_content = yaml.safe_load(f)
573
-
574
- # Find the dirac:Production hint
575
- hints = cwl_content.get("hints", [])
576
- input_dataset_dict = None
577
- for hint in hints:
578
- if hint.get("class") == "dirac:Production":
579
- input_dataset_dict = hint
580
- break
581
-
582
- if not input_dataset_dict:
583
- console.print("[red]Error:[/red] No dirac:Production hint found in CWL file")
584
- console.print(
585
- "Expected a hint with class='dirac:Production' in the 'hints' section"
586
- )
587
- raise typer.Exit(1)
575
+ if lfns:
576
+ # --- Direct LFN mode: skip BK query, resolve the provided LFNs ---
577
+ lfns_list = list(lfns)
578
+ logger.info(f"Using {len(lfns_list)} LFN(s) provided via --lfns")
588
579
 
589
- # Parse into InputDataset model
590
- try:
591
- input_dataset_outer = InputDataset(**input_dataset_dict)
592
- except Exception as e:
593
- console.print(f"[red]Error:[/red] Failed to parse dirac:Production hint: {e}")
594
- raise typer.Exit(1)
580
+ if output_map is None:
581
+ console.print(
582
+ "[red]Error:[/red] --output-map is required when using --lfns"
583
+ )
584
+ raise typer.Exit(1)
585
+
586
+ else:
587
+ # --- CWL hint mode: query BK and resolve LFNs from the hint ---
588
+ if pick_smallest and n_lfns is None:
589
+ console.print(
590
+ "[red]Error:[/red] --pick-smallest-lfn requires --n-lfns to be specified"
591
+ )
592
+ raise typer.Exit(1)
593
+
594
+ # Set default output paths if not provided
595
+ if output_yaml is None:
596
+ output_yaml = cwl_file.parent / f"{cwl_file.stem}-inputs.yml"
597
+ if output_map is None:
598
+ output_map = cwl_file.parent / f"{cwl_file.stem}-replica-map.json"
599
+
600
+ # Read the CWL file and extract inputDataset hint
601
+ logger.info(f"Reading CWL file: {cwl_file}")
602
+ with open(cwl_file, "r") as f:
603
+ cwl_content = yaml.safe_load(f)
604
+
605
+ # Find the dirac:Production hint
606
+ hints = cwl_content.get("hints", [])
607
+ input_dataset_dict = None
608
+ for hint in hints:
609
+ if hint.get("class") == "dirac:Production":
610
+ input_dataset_dict = hint
611
+ break
595
612
 
596
- input_dataset = input_dataset_outer.input_dataset_config
613
+ if not input_dataset_dict:
614
+ console.print(
615
+ "[red]Error:[/red] No dirac:Production hint found in CWL file"
616
+ )
617
+ console.print(
618
+ "Expected a hint with class='dirac:Production' in the 'hints' section"
619
+ )
620
+ raise typer.Exit(1)
621
+
622
+ # Parse into InputDataset model
623
+ try:
624
+ input_dataset_outer = InputDataset(**input_dataset_dict)
625
+ except Exception as e:
626
+ console.print(
627
+ f"[red]Error:[/red] Failed to parse dirac:Production hint: {e}"
628
+ )
629
+ raise typer.Exit(1)
597
630
 
598
- logger.info("Found dirac:Production hint:")
599
- logger.info(f" Event Type: {input_dataset.event_type}")
600
- logger.info(
601
- f" Config: {input_dataset.conditions_dict.configName}/{input_dataset.conditions_dict.configVersion}"
602
- )
603
- logger.info(f" Processing Pass: {input_dataset.conditions_dict.inProPass}")
631
+ input_dataset = input_dataset_outer.input_dataset_config
604
632
 
605
- # Query Bookkeeping for LFNs
606
- try:
607
- lfns_list = do_bkquery(
608
- input_dataset, numTestLFNs=n_lfns, pick_smallest=pick_smallest
633
+ logger.info("Found dirac:Production hint:")
634
+ logger.info(f" Event Type: {input_dataset.event_type}")
635
+ logger.info(
636
+ f" Config: {input_dataset.conditions_dict.configName}/{input_dataset.conditions_dict.configVersion}"
609
637
  )
610
- except Exception as e:
611
- console.print(f"[red]Error:[/red] Bookkeeping query failed: {e}")
612
- raise typer.Exit(1)
638
+ logger.info(f" Processing Pass: {input_dataset.conditions_dict.inProPass}")
613
639
 
614
- logger.info(f"Retrieved {len(lfns_list)} LFNs")
640
+ # Query Bookkeeping for LFNs
641
+ try:
642
+ lfns_list = do_bkquery(
643
+ input_dataset, numTestLFNs=n_lfns, pick_smallest=pick_smallest
644
+ )
645
+ except Exception as e:
646
+ console.print(f"[red]Error:[/red] Bookkeeping query failed: {e}")
647
+ raise typer.Exit(1)
615
648
 
616
- # Generate replica map using DIRAC
649
+ logger.info(f"Retrieved {len(lfns_list)} LFNs")
617
650
 
651
+ # Generate replica map using DIRAC
618
652
  logger.info("Generating replica map with DIRAC...")
619
653
  try:
620
654
  replica_map = dirac_make_replica_map(
@@ -629,28 +663,28 @@ def main(
629
663
  console.print(f"[red]Error:[/red] Failed to generate replica map: {e}")
630
664
  raise typer.Exit(1)
631
665
 
632
- # Generate CWL input YAML file
633
- cwl_inputs = {
634
- "input-data": [
635
- {
636
- "class": "File",
637
- "location": f"LFN:{lfn}",
638
- }
639
- for lfn in lfns_list
640
- ]
641
- }
642
-
643
- logger.info(f"Writing CWL input YAML to: {output_yaml}")
644
- with open(output_yaml, "w") as f:
645
- yaml.dump(cwl_inputs, f, default_flow_style=False, sort_keys=False)
666
+ # Write CWL input YAML (only in CWL hint mode or when output_yaml is explicitly provided)
667
+ if output_yaml is not None:
668
+ cwl_inputs = {
669
+ "input-data": [
670
+ {
671
+ "class": "File",
672
+ "location": f"LFN:{lfn}",
673
+ }
674
+ for lfn in lfns_list
675
+ ]
676
+ }
677
+ logger.info(f"Writing CWL input YAML to: {output_yaml}")
678
+ with open(output_yaml, "w") as f:
679
+ yaml.dump(cwl_inputs, f, default_flow_style=False, sort_keys=False)
646
680
 
647
681
  logger.info(f"Writing replica map to: {output_map}")
648
682
  with open(output_map, "w") as f:
649
- # Convert Pydantic model to dict for JSON serialization
650
683
  f.write(replica_map.model_dump_json(indent=2))
651
684
 
652
685
  console.print("\n[green]✓[/green] Successfully generated:")
653
- console.print(f" • Input YAML: {output_yaml}")
686
+ if output_yaml is not None:
687
+ console.print(f" • Input YAML: {output_yaml}")
654
688
  console.print(f" • Replica map: {output_map}")
655
689
  console.print(f"\nRetrieved {len(lfns_list)} LFN(s)")
656
690
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: LbAPLocal
3
- Version: 0.9.3
3
+ Version: 0.9.5
4
4
  Summary: Tool to locally run tests for AnalysisProductions
5
5
  Author: LHCb
6
6
  Project-URL: Homepage, https://gitlab.cern.ch/lhcb-dpa/analysis-productions/lbaplocal
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes