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.
- panda_server_source-0.8.0.dist-info/METADATA +55 -0
- panda_server_source-0.8.0.dist-info/RECORD +375 -0
- panda_server_source-0.8.0.dist-info/WHEEL +4 -0
- panda_server_source-0.8.0.dist-info/licenses/LICENSE.txt +202 -0
- pandajedi/__init__.py +0 -0
- pandajedi/jedibrokerage/AtlasAnalJobBroker.py +2343 -0
- pandajedi/jedibrokerage/AtlasBrokerUtils.py +1292 -0
- pandajedi/jedibrokerage/AtlasProdJobBroker.py +2064 -0
- pandajedi/jedibrokerage/AtlasProdTaskBroker.py +629 -0
- pandajedi/jedibrokerage/GenJobBroker.py +381 -0
- pandajedi/jedibrokerage/JobBrokerBase.py +133 -0
- pandajedi/jedibrokerage/TaskBrokerBase.py +15 -0
- pandajedi/jedibrokerage/__init__.py +0 -0
- pandajedi/jediconfig/__init__.py +0 -0
- pandajedi/jediconfig/jedi_config.py +40 -0
- pandajedi/jedicore/FactoryBase.py +182 -0
- pandajedi/jedicore/Interaction.py +433 -0
- pandajedi/jedicore/JediDBProxy.py +56 -0
- pandajedi/jedicore/JediDBProxyPool.py +37 -0
- pandajedi/jedicore/JediDBSchemaInfo.py +17 -0
- pandajedi/jedicore/JediException.py +13 -0
- pandajedi/jedicore/JediTaskBuffer.py +984 -0
- pandajedi/jedicore/JediTaskBufferInterface.py +50 -0
- pandajedi/jedicore/MsgWrapper.py +124 -0
- pandajedi/jedicore/ProcessUtils.py +34 -0
- pandajedi/jedicore/SiteCandidate.py +90 -0
- pandajedi/jedicore/ThreadUtils.py +205 -0
- pandajedi/jedicore/__init__.py +0 -0
- pandajedi/jediddm/AtlasDDMClient.py +1708 -0
- pandajedi/jediddm/DDMClientBase.py +16 -0
- pandajedi/jediddm/DDMInterface.py +83 -0
- pandajedi/jediddm/GenDDMClient.py +17 -0
- pandajedi/jediddm/__init__.py +0 -0
- pandajedi/jedidog/AtlasAnalWatchDog.py +648 -0
- pandajedi/jedidog/AtlasDataCarouselWatchDog.py +189 -0
- pandajedi/jedidog/AtlasDataLocalityUpdaterWatchDog.py +215 -0
- pandajedi/jedidog/AtlasProdWatchDog.py +443 -0
- pandajedi/jedidog/AtlasQueueFillerWatchDog.py +800 -0
- pandajedi/jedidog/AtlasTaskWithholderWatchDog.py +245 -0
- pandajedi/jedidog/AtlasWorkflowManagerWatchDog.py +63 -0
- pandajedi/jedidog/GenWatchDog.py +21 -0
- pandajedi/jedidog/JumboWatchDog.py +147 -0
- pandajedi/jedidog/TypicalWatchDogBase.py +122 -0
- pandajedi/jedidog/WatchDogBase.py +53 -0
- pandajedi/jedidog/__init__.py +0 -0
- pandajedi/jediexec/reniceJEDI.py +25 -0
- pandajedi/jedigen/AtlasTaskGenerator.py +110 -0
- pandajedi/jedigen/TaskGeneratorBase.py +15 -0
- pandajedi/jedigen/__init__.py +0 -0
- pandajedi/jedimsgprocessor/__init__.py +0 -0
- pandajedi/jedimsgprocessor/ai_parameter_adjuster_msg_processor +71 -0
- pandajedi/jedimsgprocessor/atlas_idds_msg_processor.py +66 -0
- pandajedi/jedimsgprocessor/base_msg_processor.py +33 -0
- pandajedi/jedimsgprocessor/forwarding_msg_processor.py +29 -0
- pandajedi/jedimsgprocessor/hpo_msg_processor.py +93 -0
- pandajedi/jedimsgprocessor/jedi_contents_feeder_msg_processor.py +63 -0
- pandajedi/jedimsgprocessor/jedi_job_generator_msg_processor.py +185 -0
- pandajedi/jedimsgprocessor/jedi_post_processor_msg_processor.py +82 -0
- pandajedi/jedimsgprocessor/kafka_msg_processor.py +44 -0
- pandajedi/jedimsgprocessor/panda_callback_msg_processor.py +182 -0
- pandajedi/jedimsgprocessor/panda_to_jedi_msg_processor.py +74 -0
- pandajedi/jedimsgprocessor/processing_msg_processor.py +134 -0
- pandajedi/jedimsgprocessor/status_report_msg_processor.py +129 -0
- pandajedi/jedimsgprocessor/tape_carousel_msg_processor.py +118 -0
- pandajedi/jedimsgprocessor/workflow_manager_msg_processor.py +89 -0
- pandajedi/jediorder/ContentsFeeder.py +785 -0
- pandajedi/jediorder/JediDaemon.py +27 -0
- pandajedi/jediorder/JediKnight.py +55 -0
- pandajedi/jediorder/JediMaster.py +238 -0
- pandajedi/jediorder/JediMsgProcessor.py +32 -0
- pandajedi/jediorder/JobBroker.py +33 -0
- pandajedi/jediorder/JobGenerator.py +2763 -0
- pandajedi/jediorder/JobSplitter.py +308 -0
- pandajedi/jediorder/JobThrottler.py +28 -0
- pandajedi/jediorder/PostProcessor.py +166 -0
- pandajedi/jediorder/TaskBroker.py +268 -0
- pandajedi/jediorder/TaskCommando.py +334 -0
- pandajedi/jediorder/TaskGenerator.py +17 -0
- pandajedi/jediorder/TaskRefiner.py +611 -0
- pandajedi/jediorder/TaskSetupper.py +17 -0
- pandajedi/jediorder/WatchDog.py +79 -0
- pandajedi/jediorder/__init__.py +0 -0
- pandajedi/jedipprocess/AtlasAnalPostProcessor.py +404 -0
- pandajedi/jedipprocess/AtlasPostProcessorUtils.py +50 -0
- pandajedi/jedipprocess/AtlasProdPostProcessor.py +178 -0
- pandajedi/jedipprocess/GenPostProcessor.py +35 -0
- pandajedi/jedipprocess/MailTemplates.py +185 -0
- pandajedi/jedipprocess/PostProcessorBase.py +269 -0
- pandajedi/jedipprocess/__init__.py +0 -0
- pandajedi/jedirefine/AtlasAnalTaskRefiner.py +259 -0
- pandajedi/jedirefine/AtlasProdTaskRefiner.py +162 -0
- pandajedi/jedirefine/GenTaskRefiner.py +61 -0
- pandajedi/jedirefine/RefinerUtils.py +154 -0
- pandajedi/jedirefine/TaskRefinerBase.py +996 -0
- pandajedi/jedirefine/__init__.py +0 -0
- pandajedi/jedisetup/AtlasTaskSetupper.py +309 -0
- pandajedi/jedisetup/GenTaskSetupper.py +16 -0
- pandajedi/jedisetup/SimpleTaskSetupper.py +152 -0
- pandajedi/jedisetup/TaskSetupperBase.py +15 -0
- pandajedi/jedisetup/__init__.py +0 -0
- pandajedi/jeditest/SchemaChecker.py +41 -0
- pandajedi/jeditest/addContWoSoTask.py +54 -0
- pandajedi/jeditest/addDataCarouselRequest.py +47 -0
- pandajedi/jeditest/addEventServiceTask.py +101 -0
- pandajedi/jeditest/addHpoTask.py +81 -0
- pandajedi/jeditest/addIDDSStageInRequest.py +56 -0
- pandajedi/jeditest/addNonAtlasTask.py +71 -0
- pandajedi/jeditest/addNonAtlasTaskEnc.py +64 -0
- pandajedi/jeditest/addTestTask.py +124 -0
- pandajedi/jeditest/addTestTaskParamToDEFT.py +70 -0
- pandajedi/jeditest/addTestTaskWithMerger.py +97 -0
- pandajedi/jeditest/brokerTest.py +78 -0
- pandajedi/jeditest/cancelDataCarouselRequest.py +35 -0
- pandajedi/jeditest/contentsFeederTest.py +28 -0
- pandajedi/jeditest/contentsFeederTestWithTask.py +18 -0
- pandajedi/jeditest/ddmTest.py +4 -0
- pandajedi/jeditest/jobGenForOneTask.py +38 -0
- pandajedi/jeditest/jobGeneratorTest.py +43 -0
- pandajedi/jeditest/jobSplitterTest.py +104 -0
- pandajedi/jeditest/jobThrottlerTest.py +22 -0
- pandajedi/jeditest/msgProcessorTest.py +9 -0
- pandajedi/jeditest/postProcessorTest.py +18 -0
- pandajedi/jeditest/resubmitDataCarouselRequest.py +35 -0
- pandajedi/jeditest/resubmitTaskParam.py +20 -0
- pandajedi/jeditest/taskBrokerTest.py +22 -0
- pandajedi/jeditest/taskBrokerTestWithTask.py +38 -0
- pandajedi/jeditest/taskBufferTest.py +5 -0
- pandajedi/jeditest/taskCommandoTest.py +28 -0
- pandajedi/jeditest/taskRefinerTest.py +30 -0
- pandajedi/jeditest/testOneTaskToRefine.py +49 -0
- pandajedi/jeditest/testOneTaskToTaskBroker.py +42 -0
- pandajedi/jeditest/testPandaDDMMap.py +62 -0
- pandajedi/jeditest/updateDataCarouselRequestParams.py +50 -0
- pandajedi/jeditest/watchDogTest.py +25 -0
- pandajedi/jeditest/workQueueTest.py +22 -0
- pandajedi/jedithrottle/AtlasAnalJobThrottler.py +19 -0
- pandajedi/jedithrottle/AtlasProdJobThrottler.py +18 -0
- pandajedi/jedithrottle/GenJobThrottler.py +26 -0
- pandajedi/jedithrottle/JobThrottlerBase.py +496 -0
- pandajedi/jedithrottle/__init__.py +0 -0
- pandaserver/__init__.py +0 -0
- pandaserver/api/__init__.py +0 -0
- pandaserver/api/v1/__init__.py +0 -0
- pandaserver/api/v1/common.py +339 -0
- pandaserver/api/v1/credential_management_api.py +372 -0
- pandaserver/api/v1/data_carousel_api.py +264 -0
- pandaserver/api/v1/event_api.py +269 -0
- pandaserver/api/v1/file_server_api.py +942 -0
- pandaserver/api/v1/harvester_api.py +445 -0
- pandaserver/api/v1/http_client.py +166 -0
- pandaserver/api/v1/idds_api.py +180 -0
- pandaserver/api/v1/job_api.py +463 -0
- pandaserver/api/v1/metaconfig_api.py +122 -0
- pandaserver/api/v1/pilot_api.py +895 -0
- pandaserver/api/v1/statistics_api.py +207 -0
- pandaserver/api/v1/system_api.py +186 -0
- pandaserver/api/v1/task_api.py +1520 -0
- pandaserver/api/v1/tests/__init__.py +0 -0
- pandaserver/api/v1/tests/credential_management_api_tests.py +116 -0
- pandaserver/api/v1/tests/data_carousel_api_tests.py +82 -0
- pandaserver/api/v1/tests/harvester_api_tests.py +188 -0
- pandaserver/api/v1/tests/idds_api_tests.py +45 -0
- pandaserver/api/v1/tests/job_api_tests.py +112 -0
- pandaserver/api/v1/tests/pilot_api_tests.py +154 -0
- pandaserver/api/v1/tests/statistics_api_tests.py +104 -0
- pandaserver/api/v1/tests/system_api_tests.py +58 -0
- pandaserver/api/v1/tests/task_api_tests.py +590 -0
- pandaserver/api/v1/version.py +2 -0
- pandaserver/api/v1/workflow_api.py +136 -0
- pandaserver/brokerage/SiteMapper.py +406 -0
- pandaserver/brokerage/__init__.py +0 -0
- pandaserver/brokerage/broker.py +272 -0
- pandaserver/config/__init__.py +0 -0
- pandaserver/config/config_utils.py +15 -0
- pandaserver/config/daemon_config.py +29 -0
- pandaserver/config/mcp_config.py +38 -0
- pandaserver/config/panda_config.py +233 -0
- pandaserver/configurator/Carbon.py +65 -0
- pandaserver/configurator/Configurator.py +908 -0
- pandaserver/configurator/__init__.py +0 -0
- pandaserver/configurator/aux.py +73 -0
- pandaserver/daemons/__init__.py +0 -0
- pandaserver/daemons/master.py +110 -0
- pandaserver/daemons/master_systemd.py +79 -0
- pandaserver/daemons/scripts/__init__.py +0 -0
- pandaserver/daemons/scripts/add_main.py +264 -0
- pandaserver/daemons/scripts/add_sub.py +221 -0
- pandaserver/daemons/scripts/cache_pilots.py +47 -0
- pandaserver/daemons/scripts/cache_schedconfig.py +286 -0
- pandaserver/daemons/scripts/carbon.py +50 -0
- pandaserver/daemons/scripts/configurator.py +94 -0
- pandaserver/daemons/scripts/copyArchive.py +1387 -0
- pandaserver/daemons/scripts/datasetManager.py +1154 -0
- pandaserver/daemons/scripts/dummy_test.py +25 -0
- pandaserver/daemons/scripts/evpPD2P.py +144 -0
- pandaserver/daemons/scripts/hs_scrapers.py +264 -0
- pandaserver/daemons/scripts/metric_collector.py +927 -0
- pandaserver/daemons/scripts/panda_activeusers_query.py +80 -0
- pandaserver/daemons/scripts/pilotStreaming.py +109 -0
- pandaserver/daemons/scripts/process_workflow_files_daemon.py +166 -0
- pandaserver/daemons/scripts/recover_lost_files_daemon.py +177 -0
- pandaserver/daemons/scripts/task_evaluator.py +405 -0
- pandaserver/daemons/scripts/tmpwatch.py +70 -0
- pandaserver/daemons/scripts/worker_synchronization.py +97 -0
- pandaserver/daemons/utils.py +753 -0
- pandaserver/dataservice/DataServiceUtils.py +323 -0
- pandaserver/dataservice/ErrorCode.py +25 -0
- pandaserver/dataservice/RecoverLostFilesCore.py +322 -0
- pandaserver/dataservice/__init__.py +0 -0
- pandaserver/dataservice/activator.py +79 -0
- pandaserver/dataservice/adder_atlas_plugin.py +1106 -0
- pandaserver/dataservice/adder_dummy_plugin.py +31 -0
- pandaserver/dataservice/adder_gen.py +954 -0
- pandaserver/dataservice/adder_plugin_base.py +27 -0
- pandaserver/dataservice/adder_result.py +75 -0
- pandaserver/dataservice/adder_simple_plugin.py +160 -0
- pandaserver/dataservice/closer.py +247 -0
- pandaserver/dataservice/closer_atlas_plugin.py +90 -0
- pandaserver/dataservice/ddm.py +1381 -0
- pandaserver/dataservice/ddm_handler.py +95 -0
- pandaserver/dataservice/dyn_data_distributer.py +824 -0
- pandaserver/dataservice/event_lookup_client_ei.py +77 -0
- pandaserver/dataservice/event_picker.py +268 -0
- pandaserver/dataservice/finisher.py +194 -0
- pandaserver/dataservice/setupper.py +225 -0
- pandaserver/dataservice/setupper_atlas_plugin.py +1851 -0
- pandaserver/dataservice/setupper_dummy_plugin.py +47 -0
- pandaserver/dataservice/setupper_plugin_base.py +67 -0
- pandaserver/jobdispatcher/DispatcherUtils.py +35 -0
- pandaserver/jobdispatcher/ErrorCode.py +19 -0
- pandaserver/jobdispatcher/JobDispatcher.py +1625 -0
- pandaserver/jobdispatcher/Protocol.py +443 -0
- pandaserver/jobdispatcher/Watcher.py +186 -0
- pandaserver/jobdispatcher/__init__.py +0 -0
- pandaserver/pandamcp/__init__.py +0 -0
- pandaserver/pandamcp/mcp_main.py +56 -0
- pandaserver/pandamcp/mcp_test_client.py +95 -0
- pandaserver/pandamcp/mcp_utils.py +74 -0
- pandaserver/proxycache/__init__.py +0 -0
- pandaserver/proxycache/panda_proxy_cache.py +240 -0
- pandaserver/proxycache/token_cache.py +141 -0
- pandaserver/server/.gacl +6 -0
- pandaserver/server/panda.py +539 -0
- pandaserver/srvcore/CoreUtils.py +572 -0
- pandaserver/srvcore/MailUtils.py +106 -0
- pandaserver/srvcore/__init__.py +0 -0
- pandaserver/srvcore/allowed_methods.py +100 -0
- pandaserver/srvcore/oidc_utils.py +152 -0
- pandaserver/srvcore/panda_request.py +196 -0
- pandaserver/srvcore/srv_msg_utils.py +42 -0
- pandaserver/taskbuffer/ConBridge.py +513 -0
- pandaserver/taskbuffer/DBProxyPool.py +95 -0
- pandaserver/taskbuffer/DataCarousel.py +3053 -0
- pandaserver/taskbuffer/DatasetSpec.py +137 -0
- pandaserver/taskbuffer/DdmSpec.py +201 -0
- pandaserver/taskbuffer/ErrorCode.py +87 -0
- pandaserver/taskbuffer/EventServiceUtils.py +396 -0
- pandaserver/taskbuffer/FileSpec.py +290 -0
- pandaserver/taskbuffer/GlobalShares.py +244 -0
- pandaserver/taskbuffer/HarvesterMetricsSpec.py +92 -0
- pandaserver/taskbuffer/Initializer.py +82 -0
- pandaserver/taskbuffer/InputChunk.py +1080 -0
- pandaserver/taskbuffer/JediCacheSpec.py +57 -0
- pandaserver/taskbuffer/JediDatasetSpec.py +588 -0
- pandaserver/taskbuffer/JediFileSpec.py +242 -0
- pandaserver/taskbuffer/JediTaskSpec.py +1687 -0
- pandaserver/taskbuffer/JobSpec.py +1006 -0
- pandaserver/taskbuffer/JobUtils.py +232 -0
- pandaserver/taskbuffer/NucleusSpec.py +116 -0
- pandaserver/taskbuffer/OraDBProxy.py +174 -0
- pandaserver/taskbuffer/PanDAMsgProcessor.py +8 -0
- pandaserver/taskbuffer/PandaDBSchemaInfo.py +18 -0
- pandaserver/taskbuffer/ParseJobXML.py +350 -0
- pandaserver/taskbuffer/PickleFileSpec.py +18 -0
- pandaserver/taskbuffer/PickleJobSpec.py +25 -0
- pandaserver/taskbuffer/PrioUtil.py +40 -0
- pandaserver/taskbuffer/ProcessGroups.py +111 -0
- pandaserver/taskbuffer/ResourceSpec.py +175 -0
- pandaserver/taskbuffer/SQLDumper.py +37 -0
- pandaserver/taskbuffer/SQLManager.py +60 -0
- pandaserver/taskbuffer/SiteSpec.py +304 -0
- pandaserver/taskbuffer/SupErrors.py +10 -0
- pandaserver/taskbuffer/TaskBuffer.py +2882 -0
- pandaserver/taskbuffer/TaskBufferInterface.py +163 -0
- pandaserver/taskbuffer/Utils.py +848 -0
- pandaserver/taskbuffer/WorkQueue.py +227 -0
- pandaserver/taskbuffer/WorkQueueMapper.py +203 -0
- pandaserver/taskbuffer/WorkerSpec.py +143 -0
- pandaserver/taskbuffer/WrappedCursor.py +487 -0
- pandaserver/taskbuffer/WrappedPickle.py +88 -0
- pandaserver/taskbuffer/WrappedPostgresConn.py +24 -0
- pandaserver/taskbuffer/__init__.py +0 -0
- pandaserver/taskbuffer/db_proxy_mods/OraDBProxy_structure.png +0 -0
- pandaserver/taskbuffer/db_proxy_mods/__init__.py +7 -0
- pandaserver/taskbuffer/db_proxy_mods/base_module.py +841 -0
- pandaserver/taskbuffer/db_proxy_mods/data_carousel_module.py +772 -0
- pandaserver/taskbuffer/db_proxy_mods/entity_module.py +3804 -0
- pandaserver/taskbuffer/db_proxy_mods/job_complex_module.py +5661 -0
- pandaserver/taskbuffer/db_proxy_mods/job_standalone_module.py +2640 -0
- pandaserver/taskbuffer/db_proxy_mods/metrics_module.py +874 -0
- pandaserver/taskbuffer/db_proxy_mods/misc_standalone_module.py +4272 -0
- pandaserver/taskbuffer/db_proxy_mods/task_complex_module.py +6172 -0
- pandaserver/taskbuffer/db_proxy_mods/task_event_module.py +4953 -0
- pandaserver/taskbuffer/db_proxy_mods/task_standalone_module.py +4999 -0
- pandaserver/taskbuffer/db_proxy_mods/task_utils_module.py +2063 -0
- pandaserver/taskbuffer/db_proxy_mods/worker_module.py +1944 -0
- pandaserver/taskbuffer/db_proxy_mods/workflow_module.py +832 -0
- pandaserver/taskbuffer/retryModule.py +552 -0
- pandaserver/taskbuffer/task_split_rules.py +308 -0
- pandaserver/taskbuffer/workflow_processor.py +249 -0
- pandaserver/taskbuffer/wrapped_oracle_conn.py +18 -0
- pandaserver/test/SchemaChecker.py +40 -0
- pandaserver/test/__init__.py +0 -0
- pandaserver/test/banUser.py +43 -0
- pandaserver/test/boostPrio.py +19 -0
- pandaserver/test/boostUser.py +35 -0
- pandaserver/test/callbackDDM.py +11 -0
- pandaserver/test/daod_on_demand.py +95 -0
- pandaserver/test/finishJob.py +184 -0
- pandaserver/test/finishTaskJEDI.py +11 -0
- pandaserver/test/getJobs.py +53 -0
- pandaserver/test/killJob.py +79 -0
- pandaserver/test/killJobLowPrio.py +99 -0
- pandaserver/test/killJobsInTask.py +56 -0
- pandaserver/test/killTask.py +80 -0
- pandaserver/test/killTaskJEDI.py +11 -0
- pandaserver/test/killUser.py +83 -0
- pandaserver/test/lsst/README.txt +7 -0
- pandaserver/test/lsst/lsstSubmit.py +139 -0
- pandaserver/test/lsst/lsstSubmitMERGEtest.py +141 -0
- pandaserver/test/lsst/lsstSubmitPhosim332.py +53 -0
- pandaserver/test/lsst/prepare-client-tarball-from-bigpanda-server.sh +41 -0
- pandaserver/test/reassignJobs.py +17 -0
- pandaserver/test/reassignSite.py +82 -0
- pandaserver/test/reassignTask.py +117 -0
- pandaserver/test/reassignWaiting.py +39 -0
- pandaserver/test/recoverLostFiles.py +7 -0
- pandaserver/test/reloadInputDS.py +51 -0
- pandaserver/test/sendCommandToJob.py +26 -0
- pandaserver/test/setDebugMode.py +38 -0
- pandaserver/test/setPriority.py +28 -0
- pandaserver/test/testEvgen.py +60 -0
- pandaserver/test/testEvgen17.py +58 -0
- pandaserver/test/testG4sim.py +81 -0
- pandaserver/test/testG4sim17.py +90 -0
- pandaserver/test/testGlobalShares.py +131 -0
- pandaserver/test/testReco.py +103 -0
- pandaserver/test/testSimulReco14.py +98 -0
- pandaserver/test/testSiteMap.py +26 -0
- pandaserver/test/testUpdateWorkerPilotStatus.py +9 -0
- pandaserver/userinterface/Client.py +1686 -0
- pandaserver/userinterface/UserIF.py +1799 -0
- pandaserver/userinterface/__init__.py +0 -0
- pandaserver/workflow/__init__.py +0 -0
- pandaserver/workflow/data_handler_plugins/base_data_handler.py +48 -0
- pandaserver/workflow/data_handler_plugins/ddm_collection_data_handler.py +100 -0
- pandaserver/workflow/data_handler_plugins/panda_task_data_handler.py +140 -0
- pandaserver/workflow/pcwl_test.py +122 -0
- pandaserver/workflow/pcwl_utils.py +384 -0
- pandaserver/workflow/psnakemake_container.json +68 -0
- pandaserver/workflow/psnakemake_task.json +62 -0
- pandaserver/workflow/psnakemake_test.py +60 -0
- pandaserver/workflow/snakeparser/__init__.py +3 -0
- pandaserver/workflow/snakeparser/extensions.py +74 -0
- pandaserver/workflow/snakeparser/log.py +53 -0
- pandaserver/workflow/snakeparser/names.py +3 -0
- pandaserver/workflow/snakeparser/parser.py +332 -0
- pandaserver/workflow/snakeparser/utils.py +29 -0
- pandaserver/workflow/step_handler_plugins/base_step_handler.py +85 -0
- pandaserver/workflow/step_handler_plugins/panda_task_step_handler.py +280 -0
- pandaserver/workflow/workflow_base.py +531 -0
- pandaserver/workflow/workflow_core.py +1974 -0
- pandaserver/workflow/workflow_core_smoketest.py +388 -0
- pandaserver/workflow/workflow_parser.py +222 -0
- pandaserver/workflow/workflow_utils.py +1047 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from pandaserver.taskbuffer.JobSpec import JobSpec
|
|
4
|
+
|
|
5
|
+
# status codes for each event range
|
|
6
|
+
ST_ready = 0
|
|
7
|
+
ST_sent = 1
|
|
8
|
+
ST_running = 2
|
|
9
|
+
ST_finished = 3
|
|
10
|
+
ST_cancelled = 4
|
|
11
|
+
ST_discarded = 5
|
|
12
|
+
ST_done = 6
|
|
13
|
+
ST_failed = 7
|
|
14
|
+
ST_fatal = 8
|
|
15
|
+
ST_merged = 9
|
|
16
|
+
ST_corrupted = 10
|
|
17
|
+
ST_reserved_fail = 98
|
|
18
|
+
ST_reserved_get = 99
|
|
19
|
+
|
|
20
|
+
ES_status_map = {
|
|
21
|
+
ST_ready: "ready",
|
|
22
|
+
ST_sent: "sent",
|
|
23
|
+
ST_running: "running",
|
|
24
|
+
ST_finished: "finished",
|
|
25
|
+
ST_cancelled: "cancelled",
|
|
26
|
+
ST_discarded: "discarded",
|
|
27
|
+
ST_done: "done",
|
|
28
|
+
ST_failed: "failed",
|
|
29
|
+
ST_fatal: "fatal",
|
|
30
|
+
ST_merged: "merged",
|
|
31
|
+
ST_corrupted: "corrupted",
|
|
32
|
+
ST_reserved_fail: "reserved_fail",
|
|
33
|
+
ST_reserved_get: "reserved_get",
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# identifiers for specialHandling
|
|
37
|
+
esHeader = "es:"
|
|
38
|
+
singleConsumerType = {"runonce": "1", "storeonce": "2"}
|
|
39
|
+
|
|
40
|
+
# tags for special handling. check JobSpec._tagForSH for duplication
|
|
41
|
+
esToken = "eventservice"
|
|
42
|
+
esMergeToken = "esmerge"
|
|
43
|
+
dynamicNumEventsToken = JobSpec._tagForSH["dynamicNumEvents"]
|
|
44
|
+
mergeAtOsToken = JobSpec._tagForSH["mergeAtOs"]
|
|
45
|
+
resurrectConsumersToken = JobSpec._tagForSH["resurrectConsumers"]
|
|
46
|
+
singleToken = JobSpec._tagForSH["jobCloning"]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# values for job.eventService
|
|
50
|
+
esJobFlagNumber = 1
|
|
51
|
+
esMergeJobFlagNumber = 2
|
|
52
|
+
jobCloningFlagNumber = 3
|
|
53
|
+
jumboJobFlagNumber = 4
|
|
54
|
+
coJumboJobFlagNumber = 5
|
|
55
|
+
fineGrainedFlagNumber = 6
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# values for task.eventService
|
|
59
|
+
TASK_NORMAL = 0
|
|
60
|
+
TASK_EVENT_SERVICE = 1
|
|
61
|
+
TASK_JOB_CLONING = 2
|
|
62
|
+
TASK_FINE_GRAINED = 3
|
|
63
|
+
|
|
64
|
+
# values for event.is_jumbo
|
|
65
|
+
eventTableIsJumbo = 1
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# siteid for waiting co-jumbo jobs
|
|
69
|
+
siteIdForWaitingCoJumboJobs = "WAITING_CO_JUMBO"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# relation type for jobsets
|
|
73
|
+
relationTypeJS_ID = "jobset_id"
|
|
74
|
+
relationTypeJS_Retry = "jobset_retry"
|
|
75
|
+
relationTypeJS_Map = "jobset_map"
|
|
76
|
+
relationTypesForJS = [relationTypeJS_ID, relationTypeJS_Retry, relationTypeJS_Map]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# suffix for ES dataset and files to register to DDM
|
|
80
|
+
esSuffixDDM = ".events"
|
|
81
|
+
esScopeDDM = "transient"
|
|
82
|
+
esRegStatus = "esregister"
|
|
83
|
+
|
|
84
|
+
# default max number of ES job attempt
|
|
85
|
+
defMaxAttemptEsJob = 3
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
# pilot error code
|
|
89
|
+
PEC_corruptedInputFiles = [1171, 1145, 1175, 1103]
|
|
90
|
+
PEC_corruptedInputFilesTmp = [1099]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# encode file info
|
|
94
|
+
def encodeFileInfo(
|
|
95
|
+
lfn,
|
|
96
|
+
startEvent,
|
|
97
|
+
endEvent,
|
|
98
|
+
nEventsPerWorker,
|
|
99
|
+
maxAttempt=None,
|
|
100
|
+
firstOffset=None,
|
|
101
|
+
firstEvent=None,
|
|
102
|
+
):
|
|
103
|
+
if maxAttempt is None:
|
|
104
|
+
maxAttempt = 10
|
|
105
|
+
if firstOffset is None:
|
|
106
|
+
return f"{lfn}/{startEvent}/{endEvent}/{nEventsPerWorker}/{maxAttempt}^"
|
|
107
|
+
else:
|
|
108
|
+
try:
|
|
109
|
+
totalOffset = firstEvent - firstOffset
|
|
110
|
+
except Exception:
|
|
111
|
+
totalOffset = 0
|
|
112
|
+
return f"{lfn}/{startEvent}/{endEvent}/{nEventsPerWorker}/{maxAttempt}/{totalOffset}^"
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# get header for specialHandling
|
|
116
|
+
def getHeaderForES(esIndex):
|
|
117
|
+
return f"{esHeader}{esIndex}:"
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# decode file info
|
|
121
|
+
def decodeFileInfo(specialHandling):
|
|
122
|
+
eventServiceInfo = {}
|
|
123
|
+
newSpecialHandling = ""
|
|
124
|
+
esIndex = None
|
|
125
|
+
try:
|
|
126
|
+
for tmpItem in specialHandling.split(","):
|
|
127
|
+
if tmpItem.startswith(esHeader):
|
|
128
|
+
tmpItem = re.sub("^" + esHeader, "", tmpItem)
|
|
129
|
+
# look for event service index
|
|
130
|
+
tmpMatch = re.search("^(\d+):", tmpItem)
|
|
131
|
+
if tmpMatch is not None:
|
|
132
|
+
esIndex = tmpMatch.group(1)
|
|
133
|
+
tmpItem = re.sub("^(\d+):", "", tmpItem)
|
|
134
|
+
for esItem in tmpItem.split("^"):
|
|
135
|
+
if esItem == "":
|
|
136
|
+
continue
|
|
137
|
+
esItems = esItem.split("/")
|
|
138
|
+
maxAttempt = 10
|
|
139
|
+
esOffset = 0
|
|
140
|
+
if len(esItems) == 3:
|
|
141
|
+
esLFN, esEvents, esRange = esItems
|
|
142
|
+
esStartEvent = 0
|
|
143
|
+
elif len(esItems) == 5:
|
|
144
|
+
esLFN, esStartEvent, esEndEvent, esRange, maxAttempt = esItems
|
|
145
|
+
esEvents = int(esEndEvent) - int(esStartEvent) + 1
|
|
146
|
+
elif len(esItems) == 6:
|
|
147
|
+
(
|
|
148
|
+
esLFN,
|
|
149
|
+
esStartEvent,
|
|
150
|
+
esEndEvent,
|
|
151
|
+
esRange,
|
|
152
|
+
maxAttempt,
|
|
153
|
+
esOffset,
|
|
154
|
+
) = esItems
|
|
155
|
+
esEvents = int(esEndEvent) - int(esStartEvent) + 1
|
|
156
|
+
else:
|
|
157
|
+
esLFN, esStartEvent, esEndEvent, esRange = esItems
|
|
158
|
+
esEvents = int(esEndEvent) - int(esStartEvent) + 1
|
|
159
|
+
eventServiceInfo[esLFN] = {
|
|
160
|
+
"nEvents": int(esEvents),
|
|
161
|
+
"startEvent": int(esStartEvent),
|
|
162
|
+
"nEventsPerRange": int(esRange),
|
|
163
|
+
"maxAttempt": int(maxAttempt),
|
|
164
|
+
"offset": int(esOffset),
|
|
165
|
+
}
|
|
166
|
+
newSpecialHandling += f"{esToken},"
|
|
167
|
+
else:
|
|
168
|
+
newSpecialHandling += f"{tmpItem},"
|
|
169
|
+
newSpecialHandling = newSpecialHandling[:-1]
|
|
170
|
+
except Exception:
|
|
171
|
+
newSpecialHandling = specialHandling
|
|
172
|
+
return eventServiceInfo, newSpecialHandling, esIndex
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# check if event service job
|
|
176
|
+
def isEventServiceJob(job):
|
|
177
|
+
# fine-grained job
|
|
178
|
+
if is_fine_grained_job(job):
|
|
179
|
+
return False
|
|
180
|
+
return isEventServiceSH(job.specialHandling)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
# check if event service merge job
|
|
184
|
+
def isEventServiceMerge(job):
|
|
185
|
+
return isEventServiceMergeSH(job.specialHandling)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
# check if specialHandling for event service
|
|
189
|
+
def isEventServiceSH(specialHandling):
|
|
190
|
+
try:
|
|
191
|
+
if specialHandling is not None and esToken in specialHandling.split(","):
|
|
192
|
+
return True
|
|
193
|
+
except Exception:
|
|
194
|
+
pass
|
|
195
|
+
return False
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
# check if specialHandling for event service merge
|
|
199
|
+
def isEventServiceMergeSH(specialHandling):
|
|
200
|
+
try:
|
|
201
|
+
if specialHandling is not None and esMergeToken in specialHandling.split(","):
|
|
202
|
+
return True
|
|
203
|
+
except Exception:
|
|
204
|
+
pass
|
|
205
|
+
return False
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
# set event service merge
|
|
209
|
+
def setEventServiceMerge(job):
|
|
210
|
+
try:
|
|
211
|
+
# set ES flag
|
|
212
|
+
job.eventService = esMergeJobFlagNumber
|
|
213
|
+
# set gshare to express
|
|
214
|
+
job.gshare = "Express"
|
|
215
|
+
# set flag for merging
|
|
216
|
+
if job.specialHandling is None:
|
|
217
|
+
job.specialHandling = esMergeToken
|
|
218
|
+
else:
|
|
219
|
+
newSpecialHandling = ""
|
|
220
|
+
# remove flag for event service
|
|
221
|
+
for tmpFlag in job.specialHandling.split(","):
|
|
222
|
+
if tmpFlag in ["", esToken]:
|
|
223
|
+
continue
|
|
224
|
+
newSpecialHandling += tmpFlag
|
|
225
|
+
newSpecialHandling += ","
|
|
226
|
+
newSpecialHandling += esMergeToken
|
|
227
|
+
job.specialHandling = newSpecialHandling
|
|
228
|
+
# remove fake flag
|
|
229
|
+
job.removeFakeJobToIgnore()
|
|
230
|
+
except Exception:
|
|
231
|
+
pass
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
# check if specialHandling for job cloning
|
|
235
|
+
def isJobCloningSH(specialHandling):
|
|
236
|
+
try:
|
|
237
|
+
if specialHandling is not None:
|
|
238
|
+
for token in specialHandling.split(","):
|
|
239
|
+
if singleToken == token.split(":")[0]:
|
|
240
|
+
return True
|
|
241
|
+
except Exception:
|
|
242
|
+
pass
|
|
243
|
+
return False
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
# check if event service job
|
|
247
|
+
def isJobCloningJob(job):
|
|
248
|
+
return isJobCloningSH(job.specialHandling)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
# set header for job cloning
|
|
252
|
+
def setHeaderForJobCloning(specialHandling, scType):
|
|
253
|
+
if specialHandling is None:
|
|
254
|
+
specialHandling = ""
|
|
255
|
+
tokens = specialHandling.split(",")
|
|
256
|
+
while True:
|
|
257
|
+
try:
|
|
258
|
+
tokens.remove("")
|
|
259
|
+
except Exception:
|
|
260
|
+
break
|
|
261
|
+
if scType in singleConsumerType.values():
|
|
262
|
+
tokens.append(f"{singleToken}:{scType}")
|
|
263
|
+
return ",".join(tokens)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
# get consumer type
|
|
267
|
+
def getJobCloningType(job):
|
|
268
|
+
if job.specialHandling is not None:
|
|
269
|
+
for token in job.specialHandling.split(","):
|
|
270
|
+
if singleToken == token.split(":")[0]:
|
|
271
|
+
for tmpKey in singleConsumerType:
|
|
272
|
+
tmpVal = singleConsumerType[tmpKey]
|
|
273
|
+
if tmpVal == token.split(":")[-1]:
|
|
274
|
+
return tmpKey
|
|
275
|
+
return ""
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
# get consumer value
|
|
279
|
+
def getJobCloningValue(scType):
|
|
280
|
+
if scType in singleConsumerType:
|
|
281
|
+
return singleConsumerType[scType]
|
|
282
|
+
return ""
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
# set header for dynamic number of events
|
|
286
|
+
def setHeaderForDynNumEvents(specialHandling):
|
|
287
|
+
if specialHandling is None:
|
|
288
|
+
specialHandling = ""
|
|
289
|
+
tokens = specialHandling.split(",")
|
|
290
|
+
while True:
|
|
291
|
+
try:
|
|
292
|
+
tokens.remove("")
|
|
293
|
+
except Exception:
|
|
294
|
+
break
|
|
295
|
+
tokens.append(dynamicNumEventsToken)
|
|
296
|
+
return ",".join(tokens)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
# check if specialHandling for dynamic number of events
|
|
300
|
+
def isDynNumEventsSH(specialHandling):
|
|
301
|
+
try:
|
|
302
|
+
if specialHandling is not None:
|
|
303
|
+
if dynamicNumEventsToken in specialHandling.split(","):
|
|
304
|
+
return True
|
|
305
|
+
except Exception:
|
|
306
|
+
pass
|
|
307
|
+
return False
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
# remove event service header
|
|
311
|
+
def removeHeaderForES(job):
|
|
312
|
+
if job.specialHandling is not None:
|
|
313
|
+
items = job.specialHandling.split(",")
|
|
314
|
+
newItems = []
|
|
315
|
+
for item in items:
|
|
316
|
+
if re.search("^" + esHeader + ".+", item) is None:
|
|
317
|
+
newItems.append(item)
|
|
318
|
+
job.specialHandling = ",".join(newItems)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
# check if jumbo job
|
|
322
|
+
def isJumboJob(job):
|
|
323
|
+
return job.eventService == jumboJobFlagNumber
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
# check if cooperative with jumbo job
|
|
327
|
+
def isCoJumboJob(job):
|
|
328
|
+
return job.eventService == coJumboJobFlagNumber
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
# set header for merge at OS
|
|
332
|
+
def setHeaderForMergeAtOS(specialHandling):
|
|
333
|
+
if specialHandling is None:
|
|
334
|
+
specialHandling = ""
|
|
335
|
+
tokens = specialHandling.split(",")
|
|
336
|
+
while True:
|
|
337
|
+
try:
|
|
338
|
+
tokens.remove("")
|
|
339
|
+
except Exception:
|
|
340
|
+
break
|
|
341
|
+
if mergeAtOsToken not in tokens:
|
|
342
|
+
tokens.append(mergeAtOsToken)
|
|
343
|
+
return ",".join(tokens)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
# check if specialHandling for merge at OS
|
|
347
|
+
def isMergeAtOS(specialHandling):
|
|
348
|
+
try:
|
|
349
|
+
if specialHandling is not None:
|
|
350
|
+
if mergeAtOsToken in specialHandling.split(","):
|
|
351
|
+
return True
|
|
352
|
+
except Exception:
|
|
353
|
+
pass
|
|
354
|
+
return False
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
# get dataset name for event service
|
|
358
|
+
def getEsDatasetName(taskID):
|
|
359
|
+
esDataset = f"{esScopeDDM}:{taskID}{esSuffixDDM}"
|
|
360
|
+
return esDataset
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
# set header to resurrect consumers
|
|
364
|
+
def setHeaderToResurrectConsumers(specialHandling):
|
|
365
|
+
if specialHandling is None:
|
|
366
|
+
specialHandling = ""
|
|
367
|
+
tokens = specialHandling.split(",")
|
|
368
|
+
while True:
|
|
369
|
+
try:
|
|
370
|
+
tokens.remove("")
|
|
371
|
+
except Exception:
|
|
372
|
+
break
|
|
373
|
+
if resurrectConsumersToken not in tokens:
|
|
374
|
+
tokens.append(resurrectConsumersToken)
|
|
375
|
+
return ",".join(tokens)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
# check if specialHandling to resurrect consumers
|
|
379
|
+
def isResurrectConsumers(specialHandling):
|
|
380
|
+
try:
|
|
381
|
+
if specialHandling is not None:
|
|
382
|
+
if resurrectConsumersToken in specialHandling.split(","):
|
|
383
|
+
return True
|
|
384
|
+
except Exception:
|
|
385
|
+
pass
|
|
386
|
+
return False
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
# check if fine-grained job
|
|
390
|
+
def is_fine_grained_job(job):
|
|
391
|
+
return job.eventService == fineGrainedFlagNumber
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
# set fine-grained
|
|
395
|
+
def set_fine_grained(job):
|
|
396
|
+
job.eventService = fineGrainedFlagNumber
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
"""
|
|
2
|
+
file specification
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import datetime
|
|
7
|
+
|
|
8
|
+
reserveChangedState = False
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FileSpec(object):
|
|
12
|
+
# attributes
|
|
13
|
+
_attributes = (
|
|
14
|
+
"row_ID",
|
|
15
|
+
"PandaID",
|
|
16
|
+
"GUID",
|
|
17
|
+
"lfn",
|
|
18
|
+
"type",
|
|
19
|
+
"dataset",
|
|
20
|
+
"status",
|
|
21
|
+
"prodDBlock",
|
|
22
|
+
"prodDBlockToken",
|
|
23
|
+
"dispatchDBlock",
|
|
24
|
+
"dispatchDBlockToken",
|
|
25
|
+
"destinationDBlock",
|
|
26
|
+
"destinationDBlockToken",
|
|
27
|
+
"destinationSE",
|
|
28
|
+
"fsize",
|
|
29
|
+
"md5sum",
|
|
30
|
+
"checksum",
|
|
31
|
+
"scope",
|
|
32
|
+
"jediTaskID",
|
|
33
|
+
"datasetID",
|
|
34
|
+
"fileID",
|
|
35
|
+
"attemptNr",
|
|
36
|
+
)
|
|
37
|
+
# slots
|
|
38
|
+
__slots__ = _attributes + (
|
|
39
|
+
"_owner",
|
|
40
|
+
"_changedAttrs",
|
|
41
|
+
"_oldPandaID",
|
|
42
|
+
"_reserveChangedState",
|
|
43
|
+
)
|
|
44
|
+
# attributes which have 0 by default
|
|
45
|
+
_zeroAttrs = ("fsize",)
|
|
46
|
+
# mapping between sequence and attr
|
|
47
|
+
_seqAttrMap = {"row_ID": "ATLAS_PANDA.FILESTABLE4_ROW_ID_SEQ.nextval"}
|
|
48
|
+
|
|
49
|
+
# constructor
|
|
50
|
+
def __init__(self):
|
|
51
|
+
# install attributes
|
|
52
|
+
for attr in self._attributes:
|
|
53
|
+
object.__setattr__(self, attr, None)
|
|
54
|
+
# set owner to synchronize PandaID
|
|
55
|
+
object.__setattr__(self, "_owner", None)
|
|
56
|
+
# map of changed attributes
|
|
57
|
+
object.__setattr__(self, "_changedAttrs", {})
|
|
58
|
+
# old PandaID
|
|
59
|
+
object.__setattr__(self, "_oldPandaID", "NULL")
|
|
60
|
+
# reserve changed state at instance level
|
|
61
|
+
object.__setattr__(self, "_reserveChangedState", False)
|
|
62
|
+
|
|
63
|
+
# override __getattribute__ for SQL and PandaID
|
|
64
|
+
def __getattribute__(self, name):
|
|
65
|
+
# PandaID
|
|
66
|
+
if name == "PandaID":
|
|
67
|
+
if self._owner is None:
|
|
68
|
+
return "NULL"
|
|
69
|
+
return self._owner.PandaID
|
|
70
|
+
# others
|
|
71
|
+
ret = object.__getattribute__(self, name)
|
|
72
|
+
if ret is None:
|
|
73
|
+
return "NULL"
|
|
74
|
+
return ret
|
|
75
|
+
|
|
76
|
+
# override __setattr__ to collect the changed attributes
|
|
77
|
+
def __setattr__(self, name, value):
|
|
78
|
+
oldVal = getattr(self, name)
|
|
79
|
+
object.__setattr__(self, name, value)
|
|
80
|
+
newVal = getattr(self, name)
|
|
81
|
+
# collect changed attributes
|
|
82
|
+
if oldVal != newVal:
|
|
83
|
+
self._changedAttrs[name] = value
|
|
84
|
+
|
|
85
|
+
# set owner
|
|
86
|
+
def setOwner(self, owner):
|
|
87
|
+
self._owner = owner
|
|
88
|
+
self._oldPandaID = self.PandaID
|
|
89
|
+
|
|
90
|
+
# reset changed attribute list
|
|
91
|
+
def resetChangedList(self):
|
|
92
|
+
self._oldPandaID = self.PandaID
|
|
93
|
+
object.__setattr__(self, "_changedAttrs", {})
|
|
94
|
+
|
|
95
|
+
# return a tuple of values
|
|
96
|
+
def values(self):
|
|
97
|
+
ret = []
|
|
98
|
+
for attr in self._attributes:
|
|
99
|
+
val = getattr(self, attr)
|
|
100
|
+
ret.append(val)
|
|
101
|
+
return tuple(ret)
|
|
102
|
+
|
|
103
|
+
# return map of values
|
|
104
|
+
def valuesMap(self, useSeq=False, onlyChanged=False):
|
|
105
|
+
ret = {}
|
|
106
|
+
for attr in self._attributes:
|
|
107
|
+
if useSeq and attr in self._seqAttrMap:
|
|
108
|
+
continue
|
|
109
|
+
if onlyChanged:
|
|
110
|
+
if attr == "PandaID":
|
|
111
|
+
if self.PandaID == self._oldPandaID:
|
|
112
|
+
continue
|
|
113
|
+
elif attr not in self._changedAttrs:
|
|
114
|
+
continue
|
|
115
|
+
val = getattr(self, attr)
|
|
116
|
+
if val == "NULL":
|
|
117
|
+
if attr in self._zeroAttrs:
|
|
118
|
+
val = 0
|
|
119
|
+
else:
|
|
120
|
+
val = None
|
|
121
|
+
ret[f":{attr}"] = val
|
|
122
|
+
return ret
|
|
123
|
+
|
|
124
|
+
# pack tuple into FileSpec
|
|
125
|
+
def pack(self, values):
|
|
126
|
+
for i in range(len(self._attributes)):
|
|
127
|
+
attr = self._attributes[i]
|
|
128
|
+
val = values[i]
|
|
129
|
+
object.__setattr__(self, attr, val)
|
|
130
|
+
|
|
131
|
+
# return state values to be pickled
|
|
132
|
+
def __getstate__(self):
|
|
133
|
+
state = []
|
|
134
|
+
for attr in self._attributes:
|
|
135
|
+
val = getattr(self, attr)
|
|
136
|
+
state.append(val)
|
|
137
|
+
if reserveChangedState or self._reserveChangedState:
|
|
138
|
+
state.append(self._changedAttrs)
|
|
139
|
+
# append owner info
|
|
140
|
+
state.append(self._owner)
|
|
141
|
+
return state
|
|
142
|
+
|
|
143
|
+
# restore state from the unpickled state values
|
|
144
|
+
def __setstate__(self, state):
|
|
145
|
+
pandaID = "NULL"
|
|
146
|
+
for i in range(len(self._attributes)):
|
|
147
|
+
if i + 1 < len(state):
|
|
148
|
+
object.__setattr__(self, self._attributes[i], state[i])
|
|
149
|
+
else:
|
|
150
|
+
object.__setattr__(self, self._attributes[i], "NULL")
|
|
151
|
+
if self._attributes[i] == "PandaID":
|
|
152
|
+
pandaID = state[i]
|
|
153
|
+
object.__setattr__(self, "_owner", state[-1])
|
|
154
|
+
object.__setattr__(self, "_oldPandaID", pandaID)
|
|
155
|
+
if not hasattr(self, "_reserveChangedState"):
|
|
156
|
+
object.__setattr__(self, "_reserveChangedState", False)
|
|
157
|
+
if reserveChangedState or self._reserveChangedState:
|
|
158
|
+
object.__setattr__(self, "_changedAttrs", state[-2])
|
|
159
|
+
else:
|
|
160
|
+
object.__setattr__(self, "_changedAttrs", {})
|
|
161
|
+
|
|
162
|
+
# return column names for INSERT
|
|
163
|
+
def columnNames(cls, withMod=False):
|
|
164
|
+
ret = ""
|
|
165
|
+
for attr in cls._attributes:
|
|
166
|
+
if ret != "":
|
|
167
|
+
ret += ","
|
|
168
|
+
ret += attr
|
|
169
|
+
# add modificationTime
|
|
170
|
+
if withMod:
|
|
171
|
+
ret += ",modificationTime"
|
|
172
|
+
return ret
|
|
173
|
+
|
|
174
|
+
columnNames = classmethod(columnNames)
|
|
175
|
+
|
|
176
|
+
# return expression of values for INSERT
|
|
177
|
+
def valuesExpression(cls):
|
|
178
|
+
ret = "VALUES("
|
|
179
|
+
for attr in cls._attributes:
|
|
180
|
+
ret += "%s"
|
|
181
|
+
if attr != cls._attributes[len(cls._attributes) - 1]:
|
|
182
|
+
ret += ","
|
|
183
|
+
ret += ")"
|
|
184
|
+
return ret
|
|
185
|
+
|
|
186
|
+
valuesExpression = classmethod(valuesExpression)
|
|
187
|
+
|
|
188
|
+
# return expression of bind variables for INSERT
|
|
189
|
+
def bindValuesExpression(cls, useSeq=False, withMod=False):
|
|
190
|
+
from pandaserver.config import panda_config
|
|
191
|
+
|
|
192
|
+
ret = "VALUES("
|
|
193
|
+
for attr in cls._attributes:
|
|
194
|
+
if useSeq and attr in cls._seqAttrMap:
|
|
195
|
+
if panda_config.backend == "mysql":
|
|
196
|
+
# mysql
|
|
197
|
+
ret += f"NULL,"
|
|
198
|
+
else:
|
|
199
|
+
# oracle
|
|
200
|
+
ret += f"{cls._seqAttrMap[attr]},"
|
|
201
|
+
else:
|
|
202
|
+
ret += f":{attr},"
|
|
203
|
+
ret = ret[:-1]
|
|
204
|
+
# add modificationTime
|
|
205
|
+
if withMod:
|
|
206
|
+
ret += ",:modificationTime"
|
|
207
|
+
ret += ")"
|
|
208
|
+
return ret
|
|
209
|
+
|
|
210
|
+
bindValuesExpression = classmethod(bindValuesExpression)
|
|
211
|
+
|
|
212
|
+
# return an expression for UPDATE
|
|
213
|
+
def updateExpression(cls):
|
|
214
|
+
ret = ""
|
|
215
|
+
for attr in cls._attributes:
|
|
216
|
+
ret = ret + attr + "=%s"
|
|
217
|
+
if attr != cls._attributes[len(cls._attributes) - 1]:
|
|
218
|
+
ret += ","
|
|
219
|
+
return ret
|
|
220
|
+
|
|
221
|
+
updateExpression = classmethod(updateExpression)
|
|
222
|
+
|
|
223
|
+
# return an expression of bind variables for UPDATE
|
|
224
|
+
def bindUpdateExpression(cls):
|
|
225
|
+
ret = ""
|
|
226
|
+
for attr in cls._attributes:
|
|
227
|
+
ret += f"{attr}=:{attr},"
|
|
228
|
+
ret = ret[:-1]
|
|
229
|
+
ret += " "
|
|
230
|
+
return ret
|
|
231
|
+
|
|
232
|
+
bindUpdateExpression = classmethod(bindUpdateExpression)
|
|
233
|
+
|
|
234
|
+
# return an expression of bind variables for UPDATE to update only changed attributes
|
|
235
|
+
def bindUpdateChangesExpression(self):
|
|
236
|
+
ret = ""
|
|
237
|
+
for attr in self._attributes:
|
|
238
|
+
if attr in self._changedAttrs or (attr == "PandaID" and self.PandaID != self._oldPandaID):
|
|
239
|
+
ret += f"{attr}=:{attr},"
|
|
240
|
+
ret = ret[:-1]
|
|
241
|
+
ret += " "
|
|
242
|
+
return ret
|
|
243
|
+
|
|
244
|
+
# check if unmerged input
|
|
245
|
+
def isUnMergedInput(self):
|
|
246
|
+
if self.type == "input" and self.dispatchDBlockToken == "TOMERGE":
|
|
247
|
+
return True
|
|
248
|
+
return False
|
|
249
|
+
|
|
250
|
+
# check if unmerged output
|
|
251
|
+
def isUnMergedOutput(self):
|
|
252
|
+
if self.type in ["output", "log"] and self.destinationDBlockToken == "TOMERGE":
|
|
253
|
+
return True
|
|
254
|
+
return False
|
|
255
|
+
|
|
256
|
+
# allow no output
|
|
257
|
+
def allowNoOutput(self):
|
|
258
|
+
if self.dispatchDBlockToken in ["NULL", None, ""]:
|
|
259
|
+
items = []
|
|
260
|
+
else:
|
|
261
|
+
items = self.dispatchDBlockToken.split(",")
|
|
262
|
+
if "an" not in items:
|
|
263
|
+
items.append("an")
|
|
264
|
+
self.dispatchDBlockToken = ",".join(items)
|
|
265
|
+
|
|
266
|
+
# check if no output is allowed
|
|
267
|
+
def isAllowedNoOutput(self):
|
|
268
|
+
try:
|
|
269
|
+
if "an" in self.dispatchDBlockToken.split(","):
|
|
270
|
+
return True
|
|
271
|
+
except Exception:
|
|
272
|
+
pass
|
|
273
|
+
return False
|
|
274
|
+
|
|
275
|
+
# dump to be json-serializable
|
|
276
|
+
def dump_to_json_serializable(self):
|
|
277
|
+
stat = self.__getstate__()[:-1]
|
|
278
|
+
# set None as _owner
|
|
279
|
+
stat.append(None)
|
|
280
|
+
return stat
|
|
281
|
+
|
|
282
|
+
# to a dictionary
|
|
283
|
+
def to_dict(self):
|
|
284
|
+
ret = {}
|
|
285
|
+
for a in self._attributes:
|
|
286
|
+
v = getattr(self, a)
|
|
287
|
+
if v == "NULL":
|
|
288
|
+
v = None
|
|
289
|
+
ret[a] = v
|
|
290
|
+
return ret
|