panda-server-source 0.8.0__py3-none-any.whl

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 (375) hide show
  1. panda_server_source-0.8.0.dist-info/METADATA +55 -0
  2. panda_server_source-0.8.0.dist-info/RECORD +375 -0
  3. panda_server_source-0.8.0.dist-info/WHEEL +4 -0
  4. panda_server_source-0.8.0.dist-info/licenses/LICENSE.txt +202 -0
  5. pandajedi/__init__.py +0 -0
  6. pandajedi/jedibrokerage/AtlasAnalJobBroker.py +2343 -0
  7. pandajedi/jedibrokerage/AtlasBrokerUtils.py +1292 -0
  8. pandajedi/jedibrokerage/AtlasProdJobBroker.py +2064 -0
  9. pandajedi/jedibrokerage/AtlasProdTaskBroker.py +629 -0
  10. pandajedi/jedibrokerage/GenJobBroker.py +381 -0
  11. pandajedi/jedibrokerage/JobBrokerBase.py +133 -0
  12. pandajedi/jedibrokerage/TaskBrokerBase.py +15 -0
  13. pandajedi/jedibrokerage/__init__.py +0 -0
  14. pandajedi/jediconfig/__init__.py +0 -0
  15. pandajedi/jediconfig/jedi_config.py +40 -0
  16. pandajedi/jedicore/FactoryBase.py +182 -0
  17. pandajedi/jedicore/Interaction.py +433 -0
  18. pandajedi/jedicore/JediDBProxy.py +56 -0
  19. pandajedi/jedicore/JediDBProxyPool.py +37 -0
  20. pandajedi/jedicore/JediDBSchemaInfo.py +17 -0
  21. pandajedi/jedicore/JediException.py +13 -0
  22. pandajedi/jedicore/JediTaskBuffer.py +984 -0
  23. pandajedi/jedicore/JediTaskBufferInterface.py +50 -0
  24. pandajedi/jedicore/MsgWrapper.py +124 -0
  25. pandajedi/jedicore/ProcessUtils.py +34 -0
  26. pandajedi/jedicore/SiteCandidate.py +90 -0
  27. pandajedi/jedicore/ThreadUtils.py +205 -0
  28. pandajedi/jedicore/__init__.py +0 -0
  29. pandajedi/jediddm/AtlasDDMClient.py +1708 -0
  30. pandajedi/jediddm/DDMClientBase.py +16 -0
  31. pandajedi/jediddm/DDMInterface.py +83 -0
  32. pandajedi/jediddm/GenDDMClient.py +17 -0
  33. pandajedi/jediddm/__init__.py +0 -0
  34. pandajedi/jedidog/AtlasAnalWatchDog.py +648 -0
  35. pandajedi/jedidog/AtlasDataCarouselWatchDog.py +189 -0
  36. pandajedi/jedidog/AtlasDataLocalityUpdaterWatchDog.py +215 -0
  37. pandajedi/jedidog/AtlasProdWatchDog.py +443 -0
  38. pandajedi/jedidog/AtlasQueueFillerWatchDog.py +800 -0
  39. pandajedi/jedidog/AtlasTaskWithholderWatchDog.py +245 -0
  40. pandajedi/jedidog/AtlasWorkflowManagerWatchDog.py +63 -0
  41. pandajedi/jedidog/GenWatchDog.py +21 -0
  42. pandajedi/jedidog/JumboWatchDog.py +147 -0
  43. pandajedi/jedidog/TypicalWatchDogBase.py +122 -0
  44. pandajedi/jedidog/WatchDogBase.py +53 -0
  45. pandajedi/jedidog/__init__.py +0 -0
  46. pandajedi/jediexec/reniceJEDI.py +25 -0
  47. pandajedi/jedigen/AtlasTaskGenerator.py +110 -0
  48. pandajedi/jedigen/TaskGeneratorBase.py +15 -0
  49. pandajedi/jedigen/__init__.py +0 -0
  50. pandajedi/jedimsgprocessor/__init__.py +0 -0
  51. pandajedi/jedimsgprocessor/ai_parameter_adjuster_msg_processor +71 -0
  52. pandajedi/jedimsgprocessor/atlas_idds_msg_processor.py +66 -0
  53. pandajedi/jedimsgprocessor/base_msg_processor.py +33 -0
  54. pandajedi/jedimsgprocessor/forwarding_msg_processor.py +29 -0
  55. pandajedi/jedimsgprocessor/hpo_msg_processor.py +93 -0
  56. pandajedi/jedimsgprocessor/jedi_contents_feeder_msg_processor.py +63 -0
  57. pandajedi/jedimsgprocessor/jedi_job_generator_msg_processor.py +185 -0
  58. pandajedi/jedimsgprocessor/jedi_post_processor_msg_processor.py +82 -0
  59. pandajedi/jedimsgprocessor/kafka_msg_processor.py +44 -0
  60. pandajedi/jedimsgprocessor/panda_callback_msg_processor.py +182 -0
  61. pandajedi/jedimsgprocessor/panda_to_jedi_msg_processor.py +74 -0
  62. pandajedi/jedimsgprocessor/processing_msg_processor.py +134 -0
  63. pandajedi/jedimsgprocessor/status_report_msg_processor.py +129 -0
  64. pandajedi/jedimsgprocessor/tape_carousel_msg_processor.py +118 -0
  65. pandajedi/jedimsgprocessor/workflow_manager_msg_processor.py +89 -0
  66. pandajedi/jediorder/ContentsFeeder.py +785 -0
  67. pandajedi/jediorder/JediDaemon.py +27 -0
  68. pandajedi/jediorder/JediKnight.py +55 -0
  69. pandajedi/jediorder/JediMaster.py +238 -0
  70. pandajedi/jediorder/JediMsgProcessor.py +32 -0
  71. pandajedi/jediorder/JobBroker.py +33 -0
  72. pandajedi/jediorder/JobGenerator.py +2763 -0
  73. pandajedi/jediorder/JobSplitter.py +308 -0
  74. pandajedi/jediorder/JobThrottler.py +28 -0
  75. pandajedi/jediorder/PostProcessor.py +166 -0
  76. pandajedi/jediorder/TaskBroker.py +268 -0
  77. pandajedi/jediorder/TaskCommando.py +334 -0
  78. pandajedi/jediorder/TaskGenerator.py +17 -0
  79. pandajedi/jediorder/TaskRefiner.py +611 -0
  80. pandajedi/jediorder/TaskSetupper.py +17 -0
  81. pandajedi/jediorder/WatchDog.py +79 -0
  82. pandajedi/jediorder/__init__.py +0 -0
  83. pandajedi/jedipprocess/AtlasAnalPostProcessor.py +404 -0
  84. pandajedi/jedipprocess/AtlasPostProcessorUtils.py +50 -0
  85. pandajedi/jedipprocess/AtlasProdPostProcessor.py +178 -0
  86. pandajedi/jedipprocess/GenPostProcessor.py +35 -0
  87. pandajedi/jedipprocess/MailTemplates.py +185 -0
  88. pandajedi/jedipprocess/PostProcessorBase.py +269 -0
  89. pandajedi/jedipprocess/__init__.py +0 -0
  90. pandajedi/jedirefine/AtlasAnalTaskRefiner.py +259 -0
  91. pandajedi/jedirefine/AtlasProdTaskRefiner.py +162 -0
  92. pandajedi/jedirefine/GenTaskRefiner.py +61 -0
  93. pandajedi/jedirefine/RefinerUtils.py +154 -0
  94. pandajedi/jedirefine/TaskRefinerBase.py +996 -0
  95. pandajedi/jedirefine/__init__.py +0 -0
  96. pandajedi/jedisetup/AtlasTaskSetupper.py +309 -0
  97. pandajedi/jedisetup/GenTaskSetupper.py +16 -0
  98. pandajedi/jedisetup/SimpleTaskSetupper.py +152 -0
  99. pandajedi/jedisetup/TaskSetupperBase.py +15 -0
  100. pandajedi/jedisetup/__init__.py +0 -0
  101. pandajedi/jeditest/SchemaChecker.py +41 -0
  102. pandajedi/jeditest/addContWoSoTask.py +54 -0
  103. pandajedi/jeditest/addDataCarouselRequest.py +47 -0
  104. pandajedi/jeditest/addEventServiceTask.py +101 -0
  105. pandajedi/jeditest/addHpoTask.py +81 -0
  106. pandajedi/jeditest/addIDDSStageInRequest.py +56 -0
  107. pandajedi/jeditest/addNonAtlasTask.py +71 -0
  108. pandajedi/jeditest/addNonAtlasTaskEnc.py +64 -0
  109. pandajedi/jeditest/addTestTask.py +124 -0
  110. pandajedi/jeditest/addTestTaskParamToDEFT.py +70 -0
  111. pandajedi/jeditest/addTestTaskWithMerger.py +97 -0
  112. pandajedi/jeditest/brokerTest.py +78 -0
  113. pandajedi/jeditest/cancelDataCarouselRequest.py +35 -0
  114. pandajedi/jeditest/contentsFeederTest.py +28 -0
  115. pandajedi/jeditest/contentsFeederTestWithTask.py +18 -0
  116. pandajedi/jeditest/ddmTest.py +4 -0
  117. pandajedi/jeditest/jobGenForOneTask.py +38 -0
  118. pandajedi/jeditest/jobGeneratorTest.py +43 -0
  119. pandajedi/jeditest/jobSplitterTest.py +104 -0
  120. pandajedi/jeditest/jobThrottlerTest.py +22 -0
  121. pandajedi/jeditest/msgProcessorTest.py +9 -0
  122. pandajedi/jeditest/postProcessorTest.py +18 -0
  123. pandajedi/jeditest/resubmitDataCarouselRequest.py +35 -0
  124. pandajedi/jeditest/resubmitTaskParam.py +20 -0
  125. pandajedi/jeditest/taskBrokerTest.py +22 -0
  126. pandajedi/jeditest/taskBrokerTestWithTask.py +38 -0
  127. pandajedi/jeditest/taskBufferTest.py +5 -0
  128. pandajedi/jeditest/taskCommandoTest.py +28 -0
  129. pandajedi/jeditest/taskRefinerTest.py +30 -0
  130. pandajedi/jeditest/testOneTaskToRefine.py +49 -0
  131. pandajedi/jeditest/testOneTaskToTaskBroker.py +42 -0
  132. pandajedi/jeditest/testPandaDDMMap.py +62 -0
  133. pandajedi/jeditest/updateDataCarouselRequestParams.py +50 -0
  134. pandajedi/jeditest/watchDogTest.py +25 -0
  135. pandajedi/jeditest/workQueueTest.py +22 -0
  136. pandajedi/jedithrottle/AtlasAnalJobThrottler.py +19 -0
  137. pandajedi/jedithrottle/AtlasProdJobThrottler.py +18 -0
  138. pandajedi/jedithrottle/GenJobThrottler.py +26 -0
  139. pandajedi/jedithrottle/JobThrottlerBase.py +496 -0
  140. pandajedi/jedithrottle/__init__.py +0 -0
  141. pandaserver/__init__.py +0 -0
  142. pandaserver/api/__init__.py +0 -0
  143. pandaserver/api/v1/__init__.py +0 -0
  144. pandaserver/api/v1/common.py +339 -0
  145. pandaserver/api/v1/credential_management_api.py +372 -0
  146. pandaserver/api/v1/data_carousel_api.py +264 -0
  147. pandaserver/api/v1/event_api.py +269 -0
  148. pandaserver/api/v1/file_server_api.py +942 -0
  149. pandaserver/api/v1/harvester_api.py +445 -0
  150. pandaserver/api/v1/http_client.py +166 -0
  151. pandaserver/api/v1/idds_api.py +180 -0
  152. pandaserver/api/v1/job_api.py +463 -0
  153. pandaserver/api/v1/metaconfig_api.py +122 -0
  154. pandaserver/api/v1/pilot_api.py +895 -0
  155. pandaserver/api/v1/statistics_api.py +207 -0
  156. pandaserver/api/v1/system_api.py +186 -0
  157. pandaserver/api/v1/task_api.py +1520 -0
  158. pandaserver/api/v1/tests/__init__.py +0 -0
  159. pandaserver/api/v1/tests/credential_management_api_tests.py +116 -0
  160. pandaserver/api/v1/tests/data_carousel_api_tests.py +82 -0
  161. pandaserver/api/v1/tests/harvester_api_tests.py +188 -0
  162. pandaserver/api/v1/tests/idds_api_tests.py +45 -0
  163. pandaserver/api/v1/tests/job_api_tests.py +112 -0
  164. pandaserver/api/v1/tests/pilot_api_tests.py +154 -0
  165. pandaserver/api/v1/tests/statistics_api_tests.py +104 -0
  166. pandaserver/api/v1/tests/system_api_tests.py +58 -0
  167. pandaserver/api/v1/tests/task_api_tests.py +590 -0
  168. pandaserver/api/v1/version.py +2 -0
  169. pandaserver/api/v1/workflow_api.py +136 -0
  170. pandaserver/brokerage/SiteMapper.py +406 -0
  171. pandaserver/brokerage/__init__.py +0 -0
  172. pandaserver/brokerage/broker.py +272 -0
  173. pandaserver/config/__init__.py +0 -0
  174. pandaserver/config/config_utils.py +15 -0
  175. pandaserver/config/daemon_config.py +29 -0
  176. pandaserver/config/mcp_config.py +38 -0
  177. pandaserver/config/panda_config.py +233 -0
  178. pandaserver/configurator/Carbon.py +65 -0
  179. pandaserver/configurator/Configurator.py +908 -0
  180. pandaserver/configurator/__init__.py +0 -0
  181. pandaserver/configurator/aux.py +73 -0
  182. pandaserver/daemons/__init__.py +0 -0
  183. pandaserver/daemons/master.py +110 -0
  184. pandaserver/daemons/master_systemd.py +79 -0
  185. pandaserver/daemons/scripts/__init__.py +0 -0
  186. pandaserver/daemons/scripts/add_main.py +264 -0
  187. pandaserver/daemons/scripts/add_sub.py +221 -0
  188. pandaserver/daemons/scripts/cache_pilots.py +47 -0
  189. pandaserver/daemons/scripts/cache_schedconfig.py +286 -0
  190. pandaserver/daemons/scripts/carbon.py +50 -0
  191. pandaserver/daemons/scripts/configurator.py +94 -0
  192. pandaserver/daemons/scripts/copyArchive.py +1387 -0
  193. pandaserver/daemons/scripts/datasetManager.py +1154 -0
  194. pandaserver/daemons/scripts/dummy_test.py +25 -0
  195. pandaserver/daemons/scripts/evpPD2P.py +144 -0
  196. pandaserver/daemons/scripts/hs_scrapers.py +264 -0
  197. pandaserver/daemons/scripts/metric_collector.py +927 -0
  198. pandaserver/daemons/scripts/panda_activeusers_query.py +80 -0
  199. pandaserver/daemons/scripts/pilotStreaming.py +109 -0
  200. pandaserver/daemons/scripts/process_workflow_files_daemon.py +166 -0
  201. pandaserver/daemons/scripts/recover_lost_files_daemon.py +177 -0
  202. pandaserver/daemons/scripts/task_evaluator.py +405 -0
  203. pandaserver/daemons/scripts/tmpwatch.py +70 -0
  204. pandaserver/daemons/scripts/worker_synchronization.py +97 -0
  205. pandaserver/daemons/utils.py +753 -0
  206. pandaserver/dataservice/DataServiceUtils.py +323 -0
  207. pandaserver/dataservice/ErrorCode.py +25 -0
  208. pandaserver/dataservice/RecoverLostFilesCore.py +322 -0
  209. pandaserver/dataservice/__init__.py +0 -0
  210. pandaserver/dataservice/activator.py +79 -0
  211. pandaserver/dataservice/adder_atlas_plugin.py +1106 -0
  212. pandaserver/dataservice/adder_dummy_plugin.py +31 -0
  213. pandaserver/dataservice/adder_gen.py +954 -0
  214. pandaserver/dataservice/adder_plugin_base.py +27 -0
  215. pandaserver/dataservice/adder_result.py +75 -0
  216. pandaserver/dataservice/adder_simple_plugin.py +160 -0
  217. pandaserver/dataservice/closer.py +247 -0
  218. pandaserver/dataservice/closer_atlas_plugin.py +90 -0
  219. pandaserver/dataservice/ddm.py +1381 -0
  220. pandaserver/dataservice/ddm_handler.py +95 -0
  221. pandaserver/dataservice/dyn_data_distributer.py +824 -0
  222. pandaserver/dataservice/event_lookup_client_ei.py +77 -0
  223. pandaserver/dataservice/event_picker.py +268 -0
  224. pandaserver/dataservice/finisher.py +194 -0
  225. pandaserver/dataservice/setupper.py +225 -0
  226. pandaserver/dataservice/setupper_atlas_plugin.py +1851 -0
  227. pandaserver/dataservice/setupper_dummy_plugin.py +47 -0
  228. pandaserver/dataservice/setupper_plugin_base.py +67 -0
  229. pandaserver/jobdispatcher/DispatcherUtils.py +35 -0
  230. pandaserver/jobdispatcher/ErrorCode.py +19 -0
  231. pandaserver/jobdispatcher/JobDispatcher.py +1625 -0
  232. pandaserver/jobdispatcher/Protocol.py +443 -0
  233. pandaserver/jobdispatcher/Watcher.py +186 -0
  234. pandaserver/jobdispatcher/__init__.py +0 -0
  235. pandaserver/pandamcp/__init__.py +0 -0
  236. pandaserver/pandamcp/mcp_main.py +56 -0
  237. pandaserver/pandamcp/mcp_test_client.py +95 -0
  238. pandaserver/pandamcp/mcp_utils.py +74 -0
  239. pandaserver/proxycache/__init__.py +0 -0
  240. pandaserver/proxycache/panda_proxy_cache.py +240 -0
  241. pandaserver/proxycache/token_cache.py +141 -0
  242. pandaserver/server/.gacl +6 -0
  243. pandaserver/server/panda.py +539 -0
  244. pandaserver/srvcore/CoreUtils.py +572 -0
  245. pandaserver/srvcore/MailUtils.py +106 -0
  246. pandaserver/srvcore/__init__.py +0 -0
  247. pandaserver/srvcore/allowed_methods.py +100 -0
  248. pandaserver/srvcore/oidc_utils.py +152 -0
  249. pandaserver/srvcore/panda_request.py +196 -0
  250. pandaserver/srvcore/srv_msg_utils.py +42 -0
  251. pandaserver/taskbuffer/ConBridge.py +513 -0
  252. pandaserver/taskbuffer/DBProxyPool.py +95 -0
  253. pandaserver/taskbuffer/DataCarousel.py +3053 -0
  254. pandaserver/taskbuffer/DatasetSpec.py +137 -0
  255. pandaserver/taskbuffer/DdmSpec.py +201 -0
  256. pandaserver/taskbuffer/ErrorCode.py +87 -0
  257. pandaserver/taskbuffer/EventServiceUtils.py +396 -0
  258. pandaserver/taskbuffer/FileSpec.py +290 -0
  259. pandaserver/taskbuffer/GlobalShares.py +244 -0
  260. pandaserver/taskbuffer/HarvesterMetricsSpec.py +92 -0
  261. pandaserver/taskbuffer/Initializer.py +82 -0
  262. pandaserver/taskbuffer/InputChunk.py +1080 -0
  263. pandaserver/taskbuffer/JediCacheSpec.py +57 -0
  264. pandaserver/taskbuffer/JediDatasetSpec.py +588 -0
  265. pandaserver/taskbuffer/JediFileSpec.py +242 -0
  266. pandaserver/taskbuffer/JediTaskSpec.py +1687 -0
  267. pandaserver/taskbuffer/JobSpec.py +1006 -0
  268. pandaserver/taskbuffer/JobUtils.py +232 -0
  269. pandaserver/taskbuffer/NucleusSpec.py +116 -0
  270. pandaserver/taskbuffer/OraDBProxy.py +174 -0
  271. pandaserver/taskbuffer/PanDAMsgProcessor.py +8 -0
  272. pandaserver/taskbuffer/PandaDBSchemaInfo.py +18 -0
  273. pandaserver/taskbuffer/ParseJobXML.py +350 -0
  274. pandaserver/taskbuffer/PickleFileSpec.py +18 -0
  275. pandaserver/taskbuffer/PickleJobSpec.py +25 -0
  276. pandaserver/taskbuffer/PrioUtil.py +40 -0
  277. pandaserver/taskbuffer/ProcessGroups.py +111 -0
  278. pandaserver/taskbuffer/ResourceSpec.py +175 -0
  279. pandaserver/taskbuffer/SQLDumper.py +37 -0
  280. pandaserver/taskbuffer/SQLManager.py +60 -0
  281. pandaserver/taskbuffer/SiteSpec.py +304 -0
  282. pandaserver/taskbuffer/SupErrors.py +10 -0
  283. pandaserver/taskbuffer/TaskBuffer.py +2882 -0
  284. pandaserver/taskbuffer/TaskBufferInterface.py +163 -0
  285. pandaserver/taskbuffer/Utils.py +848 -0
  286. pandaserver/taskbuffer/WorkQueue.py +227 -0
  287. pandaserver/taskbuffer/WorkQueueMapper.py +203 -0
  288. pandaserver/taskbuffer/WorkerSpec.py +143 -0
  289. pandaserver/taskbuffer/WrappedCursor.py +487 -0
  290. pandaserver/taskbuffer/WrappedPickle.py +88 -0
  291. pandaserver/taskbuffer/WrappedPostgresConn.py +24 -0
  292. pandaserver/taskbuffer/__init__.py +0 -0
  293. pandaserver/taskbuffer/db_proxy_mods/OraDBProxy_structure.png +0 -0
  294. pandaserver/taskbuffer/db_proxy_mods/__init__.py +7 -0
  295. pandaserver/taskbuffer/db_proxy_mods/base_module.py +841 -0
  296. pandaserver/taskbuffer/db_proxy_mods/data_carousel_module.py +772 -0
  297. pandaserver/taskbuffer/db_proxy_mods/entity_module.py +3804 -0
  298. pandaserver/taskbuffer/db_proxy_mods/job_complex_module.py +5661 -0
  299. pandaserver/taskbuffer/db_proxy_mods/job_standalone_module.py +2640 -0
  300. pandaserver/taskbuffer/db_proxy_mods/metrics_module.py +874 -0
  301. pandaserver/taskbuffer/db_proxy_mods/misc_standalone_module.py +4272 -0
  302. pandaserver/taskbuffer/db_proxy_mods/task_complex_module.py +6172 -0
  303. pandaserver/taskbuffer/db_proxy_mods/task_event_module.py +4953 -0
  304. pandaserver/taskbuffer/db_proxy_mods/task_standalone_module.py +4999 -0
  305. pandaserver/taskbuffer/db_proxy_mods/task_utils_module.py +2063 -0
  306. pandaserver/taskbuffer/db_proxy_mods/worker_module.py +1944 -0
  307. pandaserver/taskbuffer/db_proxy_mods/workflow_module.py +832 -0
  308. pandaserver/taskbuffer/retryModule.py +552 -0
  309. pandaserver/taskbuffer/task_split_rules.py +308 -0
  310. pandaserver/taskbuffer/workflow_processor.py +249 -0
  311. pandaserver/taskbuffer/wrapped_oracle_conn.py +18 -0
  312. pandaserver/test/SchemaChecker.py +40 -0
  313. pandaserver/test/__init__.py +0 -0
  314. pandaserver/test/banUser.py +43 -0
  315. pandaserver/test/boostPrio.py +19 -0
  316. pandaserver/test/boostUser.py +35 -0
  317. pandaserver/test/callbackDDM.py +11 -0
  318. pandaserver/test/daod_on_demand.py +95 -0
  319. pandaserver/test/finishJob.py +184 -0
  320. pandaserver/test/finishTaskJEDI.py +11 -0
  321. pandaserver/test/getJobs.py +53 -0
  322. pandaserver/test/killJob.py +79 -0
  323. pandaserver/test/killJobLowPrio.py +99 -0
  324. pandaserver/test/killJobsInTask.py +56 -0
  325. pandaserver/test/killTask.py +80 -0
  326. pandaserver/test/killTaskJEDI.py +11 -0
  327. pandaserver/test/killUser.py +83 -0
  328. pandaserver/test/lsst/README.txt +7 -0
  329. pandaserver/test/lsst/lsstSubmit.py +139 -0
  330. pandaserver/test/lsst/lsstSubmitMERGEtest.py +141 -0
  331. pandaserver/test/lsst/lsstSubmitPhosim332.py +53 -0
  332. pandaserver/test/lsst/prepare-client-tarball-from-bigpanda-server.sh +41 -0
  333. pandaserver/test/reassignJobs.py +17 -0
  334. pandaserver/test/reassignSite.py +82 -0
  335. pandaserver/test/reassignTask.py +117 -0
  336. pandaserver/test/reassignWaiting.py +39 -0
  337. pandaserver/test/recoverLostFiles.py +7 -0
  338. pandaserver/test/reloadInputDS.py +51 -0
  339. pandaserver/test/sendCommandToJob.py +26 -0
  340. pandaserver/test/setDebugMode.py +38 -0
  341. pandaserver/test/setPriority.py +28 -0
  342. pandaserver/test/testEvgen.py +60 -0
  343. pandaserver/test/testEvgen17.py +58 -0
  344. pandaserver/test/testG4sim.py +81 -0
  345. pandaserver/test/testG4sim17.py +90 -0
  346. pandaserver/test/testGlobalShares.py +131 -0
  347. pandaserver/test/testReco.py +103 -0
  348. pandaserver/test/testSimulReco14.py +98 -0
  349. pandaserver/test/testSiteMap.py +26 -0
  350. pandaserver/test/testUpdateWorkerPilotStatus.py +9 -0
  351. pandaserver/userinterface/Client.py +1686 -0
  352. pandaserver/userinterface/UserIF.py +1799 -0
  353. pandaserver/userinterface/__init__.py +0 -0
  354. pandaserver/workflow/__init__.py +0 -0
  355. pandaserver/workflow/data_handler_plugins/base_data_handler.py +48 -0
  356. pandaserver/workflow/data_handler_plugins/ddm_collection_data_handler.py +100 -0
  357. pandaserver/workflow/data_handler_plugins/panda_task_data_handler.py +140 -0
  358. pandaserver/workflow/pcwl_test.py +122 -0
  359. pandaserver/workflow/pcwl_utils.py +384 -0
  360. pandaserver/workflow/psnakemake_container.json +68 -0
  361. pandaserver/workflow/psnakemake_task.json +62 -0
  362. pandaserver/workflow/psnakemake_test.py +60 -0
  363. pandaserver/workflow/snakeparser/__init__.py +3 -0
  364. pandaserver/workflow/snakeparser/extensions.py +74 -0
  365. pandaserver/workflow/snakeparser/log.py +53 -0
  366. pandaserver/workflow/snakeparser/names.py +3 -0
  367. pandaserver/workflow/snakeparser/parser.py +332 -0
  368. pandaserver/workflow/snakeparser/utils.py +29 -0
  369. pandaserver/workflow/step_handler_plugins/base_step_handler.py +85 -0
  370. pandaserver/workflow/step_handler_plugins/panda_task_step_handler.py +280 -0
  371. pandaserver/workflow/workflow_base.py +531 -0
  372. pandaserver/workflow/workflow_core.py +1974 -0
  373. pandaserver/workflow/workflow_core_smoketest.py +388 -0
  374. pandaserver/workflow/workflow_parser.py +222 -0
  375. pandaserver/workflow/workflow_utils.py +1047 -0
@@ -0,0 +1,57 @@
1
+ """
2
+ cache specification for JEDI
3
+
4
+ """
5
+
6
+
7
+ class JediCacheSpec(object):
8
+ # attributes
9
+ attributes = (
10
+ "main_key",
11
+ "sub_key",
12
+ "data",
13
+ "last_update",
14
+ )
15
+
16
+ # constructor
17
+ def __init__(self):
18
+ # install attributes
19
+ for attr in self.attributes:
20
+ object.__setattr__(self, attr, None)
21
+
22
+ # return map of values
23
+ def valuesMap(self):
24
+ ret = {}
25
+ for attr in self.attributes:
26
+ val = getattr(self, attr)
27
+ ret[f":{attr}"] = val
28
+ return ret
29
+
30
+ # pack tuple into JediCacheSpec
31
+ def pack(self, values):
32
+ for i, attr in enumerate(self.attributes):
33
+ val = values[i]
34
+ object.__setattr__(self, attr, val)
35
+
36
+ # return column names for INSERT
37
+ @classmethod
38
+ def columnNames(cls, prefix=None):
39
+ ret = ""
40
+ if prefix is None:
41
+ ret = ",".join(cls.attributes)
42
+ else:
43
+ ret = ",".join([f"{prefix}.{attr}" for attr in cls.attributes])
44
+ return ret
45
+
46
+ # return expression of bind variables for INSERT
47
+ @classmethod
48
+ def bindValuesExpression(cls):
49
+ values_str = ",".join([f":{attr}" for attr in cls.attributes])
50
+ ret = f"VALUES({values_str})"
51
+ return ret
52
+
53
+ # return an expression of bind variables for UPDATE
54
+ @classmethod
55
+ def bindUpdateChangesExpression(cls):
56
+ ret = ",".join(["{0}=:{0}".format(attr) for attr in cls.attributes])
57
+ return ret
@@ -0,0 +1,588 @@
1
+ """
2
+ dataset specification for JEDI
3
+
4
+ """
5
+
6
+ import math
7
+ import re
8
+
9
+ from pandacommon.pandautils.PandaUtils import get_sql_IN_bind_variables
10
+
11
+ from pandaserver.config import panda_config
12
+
13
+
14
+ class JediDatasetSpec(object):
15
+ def __str__(self):
16
+ sb = []
17
+ for key in self.__dict__:
18
+ if key == "Files":
19
+ sb.append(f"{key}='{len(self.__dict__[key])}'")
20
+ else:
21
+ sb.append(f"{key}='{self.__dict__[key]}'")
22
+ return ", ".join(sb)
23
+
24
+ def __repr__(self):
25
+ return self.__str__()
26
+
27
+ # attributes
28
+ _attributes = (
29
+ "jediTaskID",
30
+ "datasetID",
31
+ "datasetName",
32
+ "containerName",
33
+ "type",
34
+ "creationTime",
35
+ "modificationTime",
36
+ "vo",
37
+ "cloud",
38
+ "site",
39
+ "masterID",
40
+ "provenanceID",
41
+ "status",
42
+ "state",
43
+ "stateCheckTime",
44
+ "stateCheckExpiration",
45
+ "frozenTime",
46
+ "nFiles",
47
+ "nFilesToBeUsed",
48
+ "nFilesUsed",
49
+ "nFilesFinished",
50
+ "nFilesFailed",
51
+ "nFilesOnHold",
52
+ "nEvents",
53
+ "nEventsToBeUsed",
54
+ "nEventsUsed",
55
+ "lockedBy",
56
+ "lockedTime",
57
+ "attributes",
58
+ "streamName",
59
+ "storageToken",
60
+ "destination",
61
+ "templateID",
62
+ "nFilesWaiting",
63
+ "nFilesMissing",
64
+ )
65
+ # attributes which have 0 by default
66
+ _zeroAttrs = ()
67
+ # attributes to force update
68
+ _forceUpdateAttrs = ("lockedBy", "lockedTime")
69
+ # mapping between sequence and attr
70
+ _seqAttrMap = {"datasetID": f"{panda_config.schemaJEDI}.JEDI_DATASETS_ID_SEQ.nextval"}
71
+ # token for attributes
72
+ attrToken = {
73
+ "allowNoOutput": "an",
74
+ "consistencyCheck": "cc",
75
+ "eventRatio": "er",
76
+ "indexConsistent": "ic",
77
+ "mergeOnly": "mo",
78
+ "nFilesPerJob": "np",
79
+ "num_records": "nr",
80
+ "offset": "of",
81
+ "objectStore": "os",
82
+ "pseudo": "ps",
83
+ "random": "rd",
84
+ "reusable": "ru",
85
+ "transient": "tr",
86
+ "useDuplicated": "ud",
87
+ "no_staging": "ns",
88
+ }
89
+
90
+ # constructor
91
+ def __init__(self):
92
+ # install attributes
93
+ for attr in self._attributes:
94
+ object.__setattr__(self, attr, None)
95
+ # file list
96
+ object.__setattr__(self, "Files", [])
97
+ # map of changed attributes
98
+ object.__setattr__(self, "_changedAttrs", {})
99
+ # distributed
100
+ object.__setattr__(self, "distributed", False)
101
+
102
+ # override __setattr__ to collecte the changed attributes
103
+ def __setattr__(self, name, value):
104
+ oldVal = getattr(self, name)
105
+ object.__setattr__(self, name, value)
106
+ newVal = getattr(self, name)
107
+ # collect changed attributes
108
+ if oldVal != newVal or name in self._forceUpdateAttrs:
109
+ self._changedAttrs[name] = value
110
+
111
+ # add File to files list
112
+ def addFile(self, fileSpec):
113
+ # append
114
+ self.Files.append(fileSpec)
115
+
116
+ # reset changed attribute list
117
+ def resetChangedList(self):
118
+ object.__setattr__(self, "_changedAttrs", {})
119
+
120
+ # force update
121
+ def forceUpdate(self, name):
122
+ if name in self._attributes:
123
+ self._changedAttrs[name] = getattr(self, name)
124
+
125
+ # return map of values
126
+ def valuesMap(self, useSeq=False, onlyChanged=False):
127
+ ret = {}
128
+ for attr in self._attributes:
129
+ # use sequence
130
+ if useSeq and attr in self._seqAttrMap:
131
+ continue
132
+ # only changed attributes
133
+ if onlyChanged:
134
+ if attr not in self._changedAttrs:
135
+ continue
136
+ val = getattr(self, attr)
137
+ if val is None:
138
+ if attr in self._zeroAttrs:
139
+ val = 0
140
+ else:
141
+ val = None
142
+ ret[f":{attr}"] = val
143
+ return ret
144
+
145
+ # pack tuple into FileSpec
146
+ def pack(self, values):
147
+ for i in range(len(self._attributes)):
148
+ attr = self._attributes[i]
149
+ val = values[i]
150
+ object.__setattr__(self, attr, val)
151
+
152
+ # return column names for INSERT
153
+ def columnNames(cls, prefix=None):
154
+ ret = ""
155
+ for attr in cls._attributes:
156
+ if prefix is not None:
157
+ ret += f"{prefix}."
158
+ ret += f"{attr},"
159
+ ret = ret[:-1]
160
+ return ret
161
+
162
+ columnNames = classmethod(columnNames)
163
+
164
+ # return expression of bind variables for INSERT
165
+ def bindValuesExpression(cls, useSeq=True):
166
+ ret = "VALUES("
167
+ for attr in cls._attributes:
168
+ if useSeq and attr in cls._seqAttrMap:
169
+ ret += f"{cls._seqAttrMap[attr]},"
170
+ else:
171
+ ret += f":{attr},"
172
+ ret = ret[:-1]
173
+ ret += ")"
174
+ return ret
175
+
176
+ bindValuesExpression = classmethod(bindValuesExpression)
177
+
178
+ # return an expression of bind variables for UPDATE to update only changed attributes
179
+ def bindUpdateChangesExpression(self):
180
+ ret = ""
181
+ for attr in self._attributes:
182
+ if attr in self._changedAttrs:
183
+ ret += f"{attr}=:{attr},"
184
+ ret = ret[:-1]
185
+ ret += " "
186
+ return ret
187
+
188
+ # set dataset attribute
189
+ def setDatasetAttribute(self, attr):
190
+ if self.attributes is None:
191
+ self.attributes = ""
192
+ else:
193
+ self.attributes += ","
194
+ self.attributes += attr
195
+
196
+ # set dataset attribute with label
197
+ def setDatasetAttributeWithLabel(self, label):
198
+ if label not in self.attrToken:
199
+ return
200
+ attr = self.attrToken[label]
201
+ if self.attributes is None:
202
+ self.attributes = ""
203
+ else:
204
+ self.attributes += ","
205
+ self.attributes += attr
206
+
207
+ # return list of status to update contents
208
+ def statusToUpdateContents(cls):
209
+ return ["defined", "toupdate"]
210
+
211
+ statusToUpdateContents = classmethod(statusToUpdateContents)
212
+
213
+ # return list of types for input
214
+ def getInputTypes(cls):
215
+ return ["input", "pseudo_input"]
216
+
217
+ getInputTypes = classmethod(getInputTypes)
218
+
219
+ # return list of types to generate jobs
220
+ def getProcessTypes(cls):
221
+ return cls.getInputTypes() + ["pp_input"] + cls.getMergeProcessTypes()
222
+
223
+ getProcessTypes = classmethod(getProcessTypes)
224
+
225
+ # return list of types for merging
226
+ def getMergeProcessTypes(cls):
227
+ return ["trn_log", "trn_output"]
228
+
229
+ getMergeProcessTypes = classmethod(getMergeProcessTypes)
230
+
231
+ # get type of unknown input
232
+ def getUnknownInputType(cls):
233
+ return "trn_unknown"
234
+
235
+ getUnknownInputType = classmethod(getUnknownInputType)
236
+
237
+ # check if JEDI needs to keep track of file usage
238
+ def toKeepTrack(self):
239
+ if self.isNoSplit() and self.isRepeated():
240
+ return False
241
+ elif self.isReusable():
242
+ return False
243
+ else:
244
+ return True
245
+
246
+ # check if it is not split
247
+ def isNoSplit(self):
248
+ if self.attributes is not None and "nosplit" in self.attributes:
249
+ return True
250
+ else:
251
+ return False
252
+
253
+ # check if it is repeatedly used
254
+ def isRepeated(self):
255
+ if self.attributes is not None and "repeat" in self.attributes:
256
+ return True
257
+ else:
258
+ return False
259
+
260
+ # check if it is randomly used
261
+ def isRandom(self):
262
+ if self.attributes is not None and "rd" in self.attributes.split(","):
263
+ return True
264
+ else:
265
+ return False
266
+
267
+ # check if it is reusable
268
+ def isReusable(self):
269
+ if self.attributes is not None and "ru" in self.attributes.split(","):
270
+ return True
271
+ else:
272
+ return False
273
+
274
+ # check if consistency is checked
275
+ def checkConsistency(self):
276
+ if self.attributes is not None and "cc" in self.attributes.split(","):
277
+ return True
278
+ else:
279
+ return False
280
+
281
+ # set consistency is checked
282
+ def enableCheckConsistency(self):
283
+ if self.attributes in [None, ""]:
284
+ self.attributes = "cc"
285
+ elif "cc" not in self.attributes.split(","):
286
+ self.attributes += ",cc"
287
+
288
+ # check if it is pseudo
289
+ def isPseudo(self):
290
+ if self.datasetName in ["pseudo_dataset", "seq_number"] or self.type in ["pp_input"]:
291
+ return True
292
+ if self.attributes is not None and self.attrToken["pseudo"] in self.attributes.split(","):
293
+ return True
294
+ return False
295
+
296
+ # check if it is a many-time dataset which is treated as long-standing at T2s
297
+ def isManyTime(self):
298
+ if self.attributes is not None and "manytime" in self.attributes:
299
+ return True
300
+ else:
301
+ return False
302
+
303
+ # check if it is seq number
304
+ def isSeqNumber(self):
305
+ if self.datasetName in ["seq_number"]:
306
+ return True
307
+ else:
308
+ return False
309
+
310
+ # check if duplicated files are used
311
+ def useDuplicatedFiles(self):
312
+ if self.attributes is not None and ("usedup" in self.attributes or "ud" in self.attributes.split(",")):
313
+ return True
314
+ else:
315
+ return False
316
+
317
+ # check if it is a master dataset
318
+ def isMaster(self):
319
+ if self.masterID is None and self.type in self.getProcessTypes():
320
+ return True
321
+ else:
322
+ return False
323
+
324
+ # check if it is a master input dataset
325
+ def isMasterInput(self):
326
+ if self.masterID is None and self.type in self.getInputTypes():
327
+ return True
328
+ else:
329
+ return False
330
+
331
+ # remove nosplit attribute
332
+ def remAttribute(self, attrName):
333
+ if self.attributes is not None:
334
+ self.attributes = re.sub(attrName, "", self.attributes)
335
+ self.attributes = re.sub(",,", ",", self.attributes)
336
+ self.attributes = re.sub("^,", "", self.attributes)
337
+ self.attributes = re.sub(",$", "", self.attributes)
338
+ if self.attributes == "":
339
+ self.attributes = None
340
+
341
+ # remove nosplit attribute
342
+ def remNoSplit(self):
343
+ self.remAttribute("nosplit")
344
+
345
+ # remove repeat attribute
346
+ def remRepeat(self):
347
+ self.remAttribute("repeat")
348
+
349
+ # get the ratio to master
350
+ def getRatioToMaster(self):
351
+ try:
352
+ tmpMatch = re.search("ratio=(\d+(\.\d+)*)", self.attributes)
353
+ if tmpMatch is not None:
354
+ ratioStr = tmpMatch.group(1)
355
+ try:
356
+ # integer
357
+ return int(ratioStr)
358
+ except Exception:
359
+ pass
360
+ try:
361
+ # float
362
+ return float(ratioStr)
363
+ except Exception:
364
+ pass
365
+ except Exception:
366
+ pass
367
+ return 1
368
+
369
+ # get N multiplied by ratio
370
+ def getNumMultByRatio(self, num):
371
+ # no split
372
+ if self.isNoSplit():
373
+ return None
374
+ # get ratio
375
+ ratioVal = self.getRatioToMaster()
376
+ # integer or float
377
+ if isinstance(ratioVal, int):
378
+ retVal = num * ratioVal
379
+ else:
380
+ retVal = float(num) * ratioVal
381
+ retVal = int(math.ceil(retVal))
382
+ return retVal
383
+
384
+ # unique map key for output
385
+ def outputMapKey(self):
386
+ mapKey = f"{self.datasetName}#{self.provenanceID}"
387
+ return mapKey
388
+
389
+ # unique map key
390
+ def uniqueMapKey(self):
391
+ mapKey = f"{self.datasetName}#{self.datasetID}"
392
+ return mapKey
393
+
394
+ # set offset
395
+ def setOffset(self, offset):
396
+ self.setDatasetAttribute(f"{self.attrToken['offset']}={offset}")
397
+
398
+ # get offset
399
+ def getOffset(self):
400
+ if self.attributes is not None:
401
+ tmpMatch = re.search(self.attrToken["offset"] + "=(\d+)", self.attributes)
402
+ if tmpMatch is not None:
403
+ offset = int(tmpMatch.group(1))
404
+ return offset
405
+ return 0
406
+
407
+ # set number of records
408
+ def setNumRecords(self, n):
409
+ self.setDatasetAttribute(f"{self.attrToken['num_records']}={n}")
410
+
411
+ # get number of records
412
+ def getNumRecords(self):
413
+ if self.attributes is not None:
414
+ for item in self.attributes.split(","):
415
+ tmpMatch = re.search(self.attrToken["num_records"] + "=(\d+)", item)
416
+ if tmpMatch is not None:
417
+ num_records = int(tmpMatch.group(1))
418
+ return num_records
419
+ return None
420
+
421
+ # set object store
422
+ def setObjectStore(self, objectStore):
423
+ self.setDatasetAttribute(f"{self.attrToken['objectStore']}={objectStore}")
424
+
425
+ # get object store
426
+ def getObjectStore(self):
427
+ if self.attributes is not None:
428
+ tmpMatch = re.search(self.attrToken["objectStore"] + "=([^,]+)", self.attributes)
429
+ if tmpMatch is not None:
430
+ return tmpMatch.group(1)
431
+ return None
432
+
433
+ # set the number of files per job
434
+ def setNumFilesPerJob(self, num):
435
+ self.setDatasetAttribute(f"{self.attrToken['nFilesPerJob']}={num}")
436
+
437
+ # get the number of files per job
438
+ def getNumFilesPerJob(self):
439
+ if self.attributes is not None:
440
+ tmpMatch = re.search(self.attrToken["nFilesPerJob"] + "=(\d+)", self.attributes)
441
+ if tmpMatch is not None:
442
+ num = int(tmpMatch.group(1))
443
+ return num
444
+ # use continuous numbers for seq_number
445
+ if self.isSeqNumber():
446
+ return 1
447
+ return None
448
+
449
+ # check if unmerged dataset
450
+ def toMerge(self):
451
+ if self.type.startswith("trn_"):
452
+ return True
453
+ return False
454
+
455
+ # set transient
456
+ def setTransient(self, val):
457
+ if val is True:
458
+ val = 1
459
+ else:
460
+ val = 0
461
+ self.setDatasetAttribute(f"{self.attrToken['transient']}={val}")
462
+
463
+ # get transient
464
+ def getTransient(self):
465
+ if self.attributes is not None:
466
+ for item in self.attributes.split(","):
467
+ tmpMatch = re.search(self.attrToken["transient"] + "=(\d+)", item)
468
+ if tmpMatch is not None:
469
+ val = int(tmpMatch.group(1))
470
+ if val == 1:
471
+ return True
472
+ else:
473
+ return False
474
+ return None
475
+
476
+ # check if no output is allowed
477
+ def isAllowedNoOutput(self):
478
+ if self.attributes is not None and self.attrToken["allowNoOutput"] in self.attributes.split(","):
479
+ return True
480
+ else:
481
+ return False
482
+
483
+ # allow no output
484
+ def allowNoOutput(self):
485
+ if self.attributes in [None, ""]:
486
+ items = []
487
+ else:
488
+ items = self.attributes.split(",")
489
+ if self.attrToken["allowNoOutput"] not in items:
490
+ items.append(self.attrToken["allowNoOutput"])
491
+ self.attributes = ",".join(items)
492
+
493
+ # check if index consistency is required
494
+ def indexConsistent(self):
495
+ if self.attributes is not None and self.attrToken["indexConsistent"] in self.attributes.split(","):
496
+ return True
497
+ else:
498
+ return False
499
+
500
+ # set distributed
501
+ def setDistributed(self):
502
+ self.distributed = True
503
+
504
+ # reset distributed
505
+ def reset_distributed(self):
506
+ self.distributed = False
507
+
508
+ # check if distributed
509
+ def isDistributed(self):
510
+ return self.distributed
511
+
512
+ # set event ratio
513
+ def setEventRatio(self, num):
514
+ self.setDatasetAttribute(f"{self.attrToken['eventRatio']}={num}")
515
+
516
+ # get event ratio
517
+ def getEventRatio(self):
518
+ if self.attributes is not None:
519
+ for item in self.attributes.split(","):
520
+ tmpMatch = re.search(self.attrToken["eventRatio"] + "=(\d+(\.\d+)*)", item)
521
+ if tmpMatch is not None:
522
+ ratioStr = tmpMatch.group(1)
523
+ try:
524
+ # integer
525
+ return int(ratioStr)
526
+ except Exception:
527
+ pass
528
+ try:
529
+ # float
530
+ return float(ratioStr)
531
+ except Exception:
532
+ pass
533
+ return None
534
+
535
+ # set pseudo
536
+ def setPseudo(self):
537
+ if self.attributes in [None, ""]:
538
+ items = []
539
+ else:
540
+ items = self.attributes.split(",")
541
+ if self.attrToken["pseudo"] not in items:
542
+ items.append(self.attrToken["pseudo"])
543
+ self.attributes = ",".join(items)
544
+
545
+ # merge only
546
+ def is_merge_only(self):
547
+ try:
548
+ return self.attrToken["mergeOnly"] in self.attributes.split(",")
549
+ except Exception:
550
+ return False
551
+
552
+ # sort files by old PandaIDs and move files with no PandaIDs to the end
553
+ def sort_files_by_panda_ids(self):
554
+ self.Files = sorted([f for f in self.Files if f.PandaID is not None], key=lambda x: x.PandaID) + [f for f in self.Files if f.PandaID is None]
555
+
556
+ # set no staging
557
+ def set_no_staging(self, value: bool):
558
+ """
559
+ Set no_staging (ns) attribute for dataset
560
+
561
+ Args:
562
+ value (bool): value of no_staging; will set attribute = 1 for True or 0 for False
563
+ """
564
+ num_repr = 1 if value else 0
565
+ self.setDatasetAttribute(f"{self.attrToken['no_staging']}={num_repr}")
566
+
567
+ # get whether is no_staging
568
+ def is_no_staging(self) -> bool:
569
+ """
570
+ Set no_staging (ns) attribute for dataset
571
+
572
+ Returns:
573
+ bool: whether with no_staging
574
+ """
575
+ if self.attributes is not None:
576
+ for item in self.attributes.split(","):
577
+ tmpMatch = re.search(self.attrToken["no_staging"] + "=(\d+)", item)
578
+ if tmpMatch is not None:
579
+ num_repr = int(tmpMatch.group(1))
580
+ value = bool(num_repr)
581
+ return value
582
+ return False
583
+
584
+
585
+ # often-used bind variables
586
+ INPUT_TYPES_var_str, INPUT_TYPES_var_map = get_sql_IN_bind_variables(JediDatasetSpec.getInputTypes(), prefix=":type_", value_as_suffix=True)
587
+ PROCESS_TYPES_var_str, PROCESS_TYPES_var_map = get_sql_IN_bind_variables(JediDatasetSpec.getProcessTypes(), prefix=":type_", value_as_suffix=True)
588
+ MERGE_TYPES_var_str, MERGE_TYPES_var_map = get_sql_IN_bind_variables(JediDatasetSpec.getMergeProcessTypes(), prefix=":type_", value_as_suffix=True)