prefect 3.6.13.dev2__py3-none-any.whl → 3.6.14.dev1__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.
- prefect/_build_info.py +3 -3
- prefect/_internal/compatibility/blocks.py +18 -0
- prefect/client/schemas/filters.py +24 -0
- prefect/flow_engine.py +192 -10
- prefect/flows.py +61 -2
- prefect/results.py +262 -21
- prefect/runner/runner.py +29 -82
- prefect/runner/storage.py +3 -2
- prefect/server/schemas/filters.py +45 -0
- prefect/server/ui-v2/assets/{artifact-card-C8JEQRHl.js → artifact-card-DkgEVahF.js} +2 -2
- prefect/server/ui-v2/assets/{artifact-card-C8JEQRHl.js.map → artifact-card-DkgEVahF.js.map} +1 -1
- prefect/server/ui-v2/assets/{artifact._id-67V8kTg9.js → artifact._id-C7yJhkKY.js} +2 -2
- prefect/server/ui-v2/assets/{artifact._id-67V8kTg9.js.map → artifact._id-C7yJhkKY.js.map} +1 -1
- prefect/server/ui-v2/assets/{automation-wizard-DuxZ47Nn.js → automation-wizard-BLI4sqs9.js} +2 -2
- prefect/server/ui-v2/assets/{automation-wizard-DuxZ47Nn.js.map → automation-wizard-BLI4sqs9.js.map} +1 -1
- prefect/server/ui-v2/assets/{automation._id-D8S8r4Ji.js → automation._id-OLes3du9.js} +2 -2
- prefect/server/ui-v2/assets/{automation._id-D8S8r4Ji.js.map → automation._id-OLes3du9.js.map} +1 -1
- prefect/server/ui-v2/assets/{automation_._id.edit-C1fOM0Hx.js → automation_._id.edit-QrSzkDDB.js} +2 -2
- prefect/server/ui-v2/assets/{automation_._id.edit-C1fOM0Hx.js.map → automation_._id.edit-QrSzkDDB.js.map} +1 -1
- prefect/server/ui-v2/assets/{automations-header-DrijTNGi.js → automations-header-BoJc9HK8.js} +2 -2
- prefect/server/ui-v2/assets/{automations-header-DrijTNGi.js.map → automations-header-BoJc9HK8.js.map} +1 -1
- prefect/server/ui-v2/assets/{base-job-template-form-section-BDkqOkpe.js → base-job-template-form-section-Br6s0jNS.js} +2 -2
- prefect/server/ui-v2/assets/{base-job-template-form-section-BDkqOkpe.js.map → base-job-template-form-section-Br6s0jNS.js.map} +1 -1
- prefect/server/ui-v2/assets/{block-type-details-CrFHWH5D.js → block-type-details-BSbBP-Nm.js} +2 -2
- prefect/server/ui-v2/assets/{block-type-details-CrFHWH5D.js.map → block-type-details-BSbBP-Nm.js.map} +1 -1
- prefect/server/ui-v2/assets/block-type-logo-DNFERTyH.js +2 -0
- prefect/server/ui-v2/assets/{block-type-logo-WQNm0PzP.js.map → block-type-logo-DNFERTyH.js.map} +1 -1
- prefect/server/ui-v2/assets/{block._id-C3gN1Ae8.js → block._id-DO6Hulrv.js} +2 -2
- prefect/server/ui-v2/assets/{block._id-C3gN1Ae8.js.map → block._id-DO6Hulrv.js.map} +1 -1
- prefect/server/ui-v2/assets/{block_._id.edit-DzPuSvat.js → block_._id.edit-BWF0TQvv.js} +2 -2
- prefect/server/ui-v2/assets/{block_._id.edit-DzPuSvat.js.map → block_._id.edit-BWF0TQvv.js.map} +1 -1
- prefect/server/ui-v2/assets/{catalog-T-7MqsyE.js → catalog-BlaqZP0r.js} +2 -2
- prefect/server/ui-v2/assets/{catalog-T-7MqsyE.js.map → catalog-BlaqZP0r.js.map} +1 -1
- prefect/server/ui-v2/assets/{catalog_._slug-DMOI61fc.js → catalog_._slug-BZWiMtjq.js} +2 -2
- prefect/server/ui-v2/assets/{catalog_._slug-DMOI61fc.js.map → catalog_._slug-BZWiMtjq.js.map} +1 -1
- prefect/server/ui-v2/assets/{catalog_._slug_.create-l9bGUPi-.js → catalog_._slug_.create-oHffbeMs.js} +2 -2
- prefect/server/ui-v2/assets/{catalog_._slug_.create-l9bGUPi-.js.map → catalog_._slug_.create-oHffbeMs.js.map} +1 -1
- prefect/server/ui-v2/assets/{collapsible-DM-Ze5-Y.js → collapsible-D45P93xU.js} +2 -2
- prefect/server/ui-v2/assets/{collapsible-DM-Ze5-Y.js.map → collapsible-D45P93xU.js.map} +1 -1
- prefect/server/ui-v2/assets/{concurrency-limit._id-BHEt9viF.js → concurrency-limit._id-B6oyPVya.js} +2 -2
- prefect/server/ui-v2/assets/{concurrency-limit._id-BHEt9viF.js.map → concurrency-limit._id-B6oyPVya.js.map} +1 -1
- prefect/server/ui-v2/assets/{create-BMxUOyN5.js → create-CcYMd6w6.js} +2 -2
- prefect/server/ui-v2/assets/{create-BMxUOyN5.js.map → create-CcYMd6w6.js.map} +1 -1
- prefect/server/ui-v2/assets/{create-Cq-EAHVk.js → create-DK1WvDhf.js} +2 -2
- prefect/server/ui-v2/assets/{create-Cq-EAHVk.js.map → create-DK1WvDhf.js.map} +1 -1
- prefect/server/ui-v2/assets/{data-table-Bw8TZx9D.js → data-table-B_iyrrTm.js} +2 -2
- prefect/server/ui-v2/assets/{data-table-Bw8TZx9D.js.map → data-table-B_iyrrTm.js.map} +1 -1
- prefect/server/ui-v2/assets/{delete-confirmation-dialog-CTdWZlGM.js → delete-confirmation-dialog-7GKqeKy1.js} +2 -2
- prefect/server/ui-v2/assets/{delete-confirmation-dialog-CTdWZlGM.js.map → delete-confirmation-dialog-7GKqeKy1.js.map} +1 -1
- prefect/server/ui-v2/assets/{deployment-action-header-BObYqmI_.js → deployment-action-header-DrvnfE9Y.js} +2 -2
- prefect/server/ui-v2/assets/{deployment-action-header-BObYqmI_.js.map → deployment-action-header-DrvnfE9Y.js.map} +1 -1
- prefect/server/ui-v2/assets/{deployment-form-CntyhRrK.js → deployment-form-DsAij22s.js} +3 -3
- prefect/server/ui-v2/assets/{deployment-form-CntyhRrK.js.map → deployment-form-DsAij22s.js.map} +1 -1
- prefect/server/ui-v2/assets/{deployment-links-DBUSCaxB.js → deployment-links-BwqfKWQX.js} +2 -2
- prefect/server/ui-v2/assets/{deployment-links-DBUSCaxB.js.map → deployment-links-BwqfKWQX.js.map} +1 -1
- prefect/server/ui-v2/assets/{deployment._id-BXanVFA8.js → deployment._id-E5e5s6bO.js} +2 -2
- prefect/server/ui-v2/assets/{deployment._id-BXanVFA8.js.map → deployment._id-E5e5s6bO.js.map} +1 -1
- prefect/server/ui-v2/assets/{deployment._id-Q5cvHMX9.js → deployment._id-U6KrtWw0.js} +2 -2
- prefect/server/ui-v2/assets/{deployment._id-Q5cvHMX9.js.map → deployment._id-U6KrtWw0.js.map} +1 -1
- prefect/server/ui-v2/assets/deployment_._id.duplicate-C_kNyCA9.js +2 -0
- prefect/server/ui-v2/assets/{deployment_._id.duplicate-DB-4hHHc.js.map → deployment_._id.duplicate-C_kNyCA9.js.map} +1 -1
- prefect/server/ui-v2/assets/deployment_._id.edit-BP8pfTOR.js +2 -0
- prefect/server/ui-v2/assets/{deployment_._id.edit-CWf1RIGy.js.map → deployment_._id.edit-BP8pfTOR.js.map} +1 -1
- prefect/server/ui-v2/assets/{deployment_._id.run-CoHGXFoM.js → deployment_._id.run-Di3-4Mtk.js} +2 -2
- prefect/server/ui-v2/assets/{deployment_._id.run-CoHGXFoM.js.map → deployment_._id.run-Di3-4Mtk.js.map} +1 -1
- prefect/server/ui-v2/assets/{dropdown-menu-CT-s-V7d.js → dropdown-menu-iS8iJMpx.js} +2 -2
- prefect/server/ui-v2/assets/{dropdown-menu-CT-s-V7d.js.map → dropdown-menu-iS8iJMpx.js.map} +1 -1
- prefect/server/ui-v2/assets/{event._eventDate._eventId-BITo_GYL.js → event._eventDate._eventId-CG15qDSZ.js} +2 -2
- prefect/server/ui-v2/assets/{event._eventDate._eventId-BITo_GYL.js.map → event._eventDate._eventId-CG15qDSZ.js.map} +1 -1
- prefect/server/ui-v2/assets/flow-run-graph-B1vF1w0Z.js +2 -0
- prefect/server/ui-v2/assets/flow-run-graph-B1vF1w0Z.js.map +1 -0
- prefect/server/ui-v2/assets/flow-run._id-BHY61H6u.js +4 -0
- prefect/server/ui-v2/assets/flow-run._id-BHY61H6u.js.map +1 -0
- prefect/server/ui-v2/assets/{flow-run._id-BtSgRDtA.js → flow-run._id-D_eAHZ5z.js} +2 -2
- prefect/server/ui-v2/assets/{flow-run._id-BtSgRDtA.js.map → flow-run._id-D_eAHZ5z.js.map} +1 -1
- prefect/server/ui-v2/assets/{flow-run._id-Bbm9OpDi.js → flow-run._id-wco0Q19f.js} +2 -2
- prefect/server/ui-v2/assets/{flow-run._id-Bbm9OpDi.js.map → flow-run._id-wco0Q19f.js.map} +1 -1
- prefect/server/ui-v2/assets/{flow-runs-pagination-LrU9Aio8.js → flow-runs-pagination-DzGHOht3.js} +2 -2
- prefect/server/ui-v2/assets/{flow-runs-pagination-LrU9Aio8.js.map → flow-runs-pagination-DzGHOht3.js.map} +1 -1
- prefect/server/ui-v2/assets/{flow._id-BJBRokk4.js → flow._id-Dn2so3rK.js} +2 -2
- prefect/server/ui-v2/assets/{flow._id-BJBRokk4.js.map → flow._id-Dn2so3rK.js.map} +1 -1
- prefect/server/ui-v2/assets/{form-CVSlEnl8.js → form-rC8pxeRl.js} +2 -2
- prefect/server/ui-v2/assets/{form-CVSlEnl8.js.map → form-rC8pxeRl.js.map} +1 -1
- prefect/server/ui-v2/assets/{header-4plZZheZ.js → header-C0zV3WDn.js} +2 -2
- prefect/server/ui-v2/assets/{header-4plZZheZ.js.map → header-C0zV3WDn.js.map} +1 -1
- prefect/server/ui-v2/assets/{header-D3uM8_xM.js → header-C6ko3O7G.js} +2 -2
- prefect/server/ui-v2/assets/{header-D3uM8_xM.js.map → header-C6ko3O7G.js.map} +1 -1
- prefect/server/ui-v2/assets/{header-9rXZ4r39.js → header-CuAwmJ64.js} +2 -2
- prefect/server/ui-v2/assets/{header-9rXZ4r39.js.map → header-CuAwmJ64.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-6OsEYhIi.js → index-0g8aAM30.js} +2 -2
- prefect/server/ui-v2/assets/{index-6OsEYhIi.js.map → index-0g8aAM30.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-BeoNC2tJ.js → index-BIqzfifB.js} +2 -2
- prefect/server/ui-v2/assets/{index-BeoNC2tJ.js.map → index-BIqzfifB.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-ChIrfjIW.js → index-BKbBu9gL.js} +2 -2
- prefect/server/ui-v2/assets/{index-ChIrfjIW.js.map → index-BKbBu9gL.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-h9-QgNjZ.js → index-BYQ1P2TC.js} +2 -2
- prefect/server/ui-v2/assets/{index-h9-QgNjZ.js.map → index-BYQ1P2TC.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-DODEq1Pi.js → index-BdgomKuA.js} +2 -2
- prefect/server/ui-v2/assets/{index-DODEq1Pi.js.map → index-BdgomKuA.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-DqCPbST9.js → index-Benf9xn3.js} +2 -2
- prefect/server/ui-v2/assets/{index-DqCPbST9.js.map → index-Benf9xn3.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-B7xsJ-QH.js → index-BjsWjEUO.js} +2 -2
- prefect/server/ui-v2/assets/{index-B7xsJ-QH.js.map → index-BjsWjEUO.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-DicK6p3K.js → index-C3D0Re7U.js} +2 -2
- prefect/server/ui-v2/assets/{index-DicK6p3K.js.map → index-C3D0Re7U.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-BlpD74iH.js → index-CCs20W5W.js} +2 -2
- prefect/server/ui-v2/assets/{index-BlpD74iH.js.map → index-CCs20W5W.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-udb79rgq.js → index-CEStyUb-.js} +2 -2
- prefect/server/ui-v2/assets/{index-udb79rgq.js.map → index-CEStyUb-.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-tBdv6kBF.js → index-CYpFLd7y.js} +2 -2
- prefect/server/ui-v2/assets/{index-tBdv6kBF.js.map → index-CYpFLd7y.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-CDyLkbVG.js → index-CcVSC2pV.js} +2 -2
- prefect/server/ui-v2/assets/{index-CDyLkbVG.js.map → index-CcVSC2pV.js.map} +1 -1
- prefect/server/ui-v2/assets/index-Cd7pM9pk.js +17 -0
- prefect/server/ui-v2/assets/index-Cd7pM9pk.js.map +1 -0
- prefect/server/ui-v2/assets/{index-DJyKqsFO.js → index-CotXErTe.js} +2 -2
- prefect/server/ui-v2/assets/{index-DJyKqsFO.js.map → index-CotXErTe.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-DxPoKag8.js → index-D8fZaZa7.js} +2 -2
- prefect/server/ui-v2/assets/{index-DxPoKag8.js.map → index-D8fZaZa7.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-D6GJ4go1.js → index-DB2qeheX.js} +2 -2
- prefect/server/ui-v2/assets/{index-D6GJ4go1.js.map → index-DB2qeheX.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-CzCSgCK-.js → index-DvKYj8ko.js} +2 -2
- prefect/server/ui-v2/assets/{index-CzCSgCK-.js.map → index-DvKYj8ko.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-BfJLUM7N.js → index-DwkedbVy.js} +2 -2
- prefect/server/ui-v2/assets/{index-BfJLUM7N.js.map → index-DwkedbVy.js.map} +1 -1
- prefect/server/ui-v2/assets/index-b9WBW430.css +1 -0
- prefect/server/ui-v2/assets/{index-CDwJvjUM.js → index-fhrsIceD.js} +2 -2
- prefect/server/ui-v2/assets/{index-CDwJvjUM.js.map → index-fhrsIceD.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-D5v9S-lB.js → index-k2161reF.js} +2 -2
- prefect/server/ui-v2/assets/{index-D5v9S-lB.js.map → index-k2161reF.js.map} +1 -1
- prefect/server/ui-v2/assets/{index-Bj0OOguP.js → index-pE_31vXF.js} +2 -2
- prefect/server/ui-v2/assets/{index-Bj0OOguP.js.map → index-pE_31vXF.js.map} +1 -1
- prefect/server/ui-v2/assets/{json-input-Dt1icmrn.js → json-input-C9dkBSdc.js} +2 -2
- prefect/server/ui-v2/assets/{json-input-Dt1icmrn.js.map → json-input-C9dkBSdc.js.map} +1 -1
- prefect/server/ui-v2/assets/{key._key-Cyh5MBX_.js → key._key-BBVH44_R.js} +2 -2
- prefect/server/ui-v2/assets/{key._key-Cyh5MBX_.js.map → key._key-BBVH44_R.js.map} +1 -1
- prefect/server/ui-v2/assets/{lazy-markdown-BwIwKFRF.js → lazy-markdown-BoMKGRXo.js} +2 -2
- prefect/server/ui-v2/assets/{lazy-markdown-BwIwKFRF.js.map → lazy-markdown-BoMKGRXo.js.map} +1 -1
- prefect/server/ui-v2/assets/{login-DKXFVSwk.js → login-BmmIDesJ.js} +2 -2
- prefect/server/ui-v2/assets/{login-DKXFVSwk.js.map → login-BmmIDesJ.js.map} +1 -1
- prefect/server/ui-v2/assets/{markdown-input-Dp0mBlkV.js → markdown-input-C6P8cYT1.js} +2 -2
- prefect/server/ui-v2/assets/{markdown-input-Dp0mBlkV.js.map → markdown-input-C6P8cYT1.js.map} +1 -1
- prefect/server/ui-v2/assets/{python-example-snippet-BYwPjHI5.js → python-example-snippet-DPumgTpL.js} +3 -3
- prefect/server/ui-v2/assets/{python-example-snippet-BYwPjHI5.js.map → python-example-snippet-DPumgTpL.js.map} +1 -1
- prefect/server/ui-v2/assets/{python-input-y26XMqXw.js → python-input-DX4uV8MF.js} +2 -2
- prefect/server/ui-v2/assets/{python-input-y26XMqXw.js.map → python-input-DX4uV8MF.js.map} +1 -1
- prefect/server/ui-v2/assets/{radio-group-D0van45v.js → radio-group-DeNK-Ob0.js} +2 -2
- prefect/server/ui-v2/assets/{radio-group-D0van45v.js.map → radio-group-DeNK-Ob0.js.map} +1 -1
- prefect/server/ui-v2/assets/{route-error-state-CGGpuCGN.js → route-error-state-C9CbByMx.js} +2 -2
- prefect/server/ui-v2/assets/{route-error-state-CGGpuCGN.js.map → route-error-state-C9CbByMx.js.map} +1 -1
- prefect/server/ui-v2/assets/{schema-form-2tg5SXM4.js → schema-form-B45xnsnK.js} +2 -2
- prefect/server/ui-v2/assets/{schema-form-2tg5SXM4.js.map → schema-form-B45xnsnK.js.map} +1 -1
- prefect/server/ui-v2/assets/{schema-form-input-string-format-datetime-CZt6AJ4z.js → schema-form-input-string-format-datetime-BJj81bu-.js} +4 -4
- prefect/server/ui-v2/assets/{schema-form-input-string-format-datetime-CZt6AJ4z.js.map → schema-form-input-string-format-datetime-BJj81bu-.js.map} +1 -1
- prefect/server/ui-v2/assets/{settings-DDUadk_N.js → settings-CbkeWqQ9.js} +2 -2
- prefect/server/ui-v2/assets/{settings-DDUadk_N.js.map → settings-CbkeWqQ9.js.map} +1 -1
- prefect/server/ui-v2/assets/{sort-filter-D9p3cPx9.js → sort-filter-DM7SvBB0.js} +2 -2
- prefect/server/ui-v2/assets/{sort-filter-D9p3cPx9.js.map → sort-filter-DM7SvBB0.js.map} +1 -1
- prefect/server/ui-v2/assets/{table-vo9Do8sA.js → table-CEPo6xb_.js} +2 -2
- prefect/server/ui-v2/assets/{table-vo9Do8sA.js.map → table-CEPo6xb_.js.map} +1 -1
- prefect/server/ui-v2/assets/{tags-input-Ci2JQ-k3.js → tags-input-DJiZSVHp.js} +2 -2
- prefect/server/ui-v2/assets/{tags-input-Ci2JQ-k3.js.map → tags-input-DJiZSVHp.js.map} +1 -1
- prefect/server/ui-v2/assets/{task-run-concurrency-limits-reset-dialog-CJzPc2gw.js → task-run-concurrency-limits-reset-dialog-vJEkvqWp.js} +2 -2
- prefect/server/ui-v2/assets/{task-run-concurrency-limits-reset-dialog-CJzPc2gw.js.map → task-run-concurrency-limits-reset-dialog-vJEkvqWp.js.map} +1 -1
- prefect/server/ui-v2/assets/{task-run._id-D8QKG5UZ.js → task-run._id-BCnDnXrL.js} +2 -2
- prefect/server/ui-v2/assets/{task-run._id-D8QKG5UZ.js.map → task-run._id-BCnDnXrL.js.map} +1 -1
- prefect/server/ui-v2/assets/{task-run._id-CjevSs79.js → task-run._id-ByJw1K82.js} +2 -2
- prefect/server/ui-v2/assets/{task-run._id-CjevSs79.js.map → task-run._id-ByJw1K82.js.map} +1 -1
- prefect/server/ui-v2/assets/{task-runs-pagination-CifoSGct.js → task-runs-pagination-DbjB6XnY.js} +2 -2
- prefect/server/ui-v2/assets/{task-runs-pagination-CifoSGct.js.map → task-runs-pagination-DbjB6XnY.js.map} +1 -1
- prefect/server/ui-v2/assets/{textarea-BAtfAxtV.js → textarea-BX8KbLGx.js} +2 -2
- prefect/server/ui-v2/assets/{textarea-BAtfAxtV.js.map → textarea-BX8KbLGx.js.map} +1 -1
- prefect/server/ui-v2/assets/{timezone-select-QlQTZSsF.js → timezone-select-TBj2n6Ox.js} +2 -2
- prefect/server/ui-v2/assets/{timezone-select-QlQTZSsF.js.map → timezone-select-TBj2n6Ox.js.map} +1 -1
- prefect/server/ui-v2/assets/{toggle-group-BJN1vjEh.js → toggle-group-D7mfSUim.js} +2 -2
- prefect/server/ui-v2/assets/{toggle-group-BJN1vjEh.js.map → toggle-group-D7mfSUim.js.map} +1 -1
- prefect/server/ui-v2/assets/{use-delete-automation-confirmation-dialog-eOWJYPkD.js → use-delete-automation-confirmation-dialog-BpBSjz60.js} +2 -2
- prefect/server/ui-v2/assets/{use-delete-automation-confirmation-dialog-eOWJYPkD.js.map → use-delete-automation-confirmation-dialog-BpBSjz60.js.map} +1 -1
- prefect/server/ui-v2/assets/{use-delete-block-document-confirmation-dialog-BTwSeHRM.js → use-delete-block-document-confirmation-dialog-BjKsNw6b.js} +2 -2
- prefect/server/ui-v2/assets/{use-delete-block-document-confirmation-dialog-BTwSeHRM.js.map → use-delete-block-document-confirmation-dialog-BjKsNw6b.js.map} +1 -1
- prefect/server/ui-v2/assets/{use-flow-runs-selected-rows-BL_Gv9CC.js → use-flow-runs-selected-rows-B_BlBMic.js} +2 -2
- prefect/server/ui-v2/assets/{use-flow-runs-selected-rows-BL_Gv9CC.js.map → use-flow-runs-selected-rows-B_BlBMic.js.map} +1 -1
- prefect/server/ui-v2/assets/{use-get-artifacts-flow-task-runs-TSCoomjQ.js → use-get-artifacts-flow-task-runs-BfE433bC.js} +2 -2
- prefect/server/ui-v2/assets/{use-get-artifacts-flow-task-runs-TSCoomjQ.js.map → use-get-artifacts-flow-task-runs-BfE433bC.js.map} +1 -1
- prefect/server/ui-v2/assets/{use-quick-run-BMnCkwSv.js → use-quick-run-qrtcF-DD.js} +2 -2
- prefect/server/ui-v2/assets/{use-quick-run-BMnCkwSv.js.map → use-quick-run-qrtcF-DD.js.map} +1 -1
- prefect/server/ui-v2/assets/{use-stepper-C1wm66U2.js → use-stepper-CVy1_GBw.js} +2 -2
- prefect/server/ui-v2/assets/{use-stepper-C1wm66U2.js.map → use-stepper-CVy1_GBw.js.map} +1 -1
- prefect/server/ui-v2/assets/{utilities-DxRXxFOF.js → utilities-D5-00wjP.js} +2 -2
- prefect/server/ui-v2/assets/{utilities-DxRXxFOF.js.map → utilities-D5-00wjP.js.map} +1 -1
- prefect/server/ui-v2/assets/{vendor-graphs-Diy0Lo-N.js → vendor-graphs-R8z6S3Jg.js} +2 -2
- prefect/server/ui-v2/assets/{vendor-graphs-Diy0Lo-N.js.map → vendor-graphs-R8z6S3Jg.js.map} +1 -1
- prefect/server/ui-v2/assets/{work-pool-filter-PudrkZYj.js → work-pool-filter-D8MkTbSW.js} +2 -2
- prefect/server/ui-v2/assets/{work-pool-filter-PudrkZYj.js.map → work-pool-filter-D8MkTbSW.js.map} +1 -1
- prefect/server/ui-v2/assets/{work-pool-queue-toggle-BAOrV_0R.js → work-pool-queue-toggle-CbI7Gfu5.js} +2 -2
- prefect/server/ui-v2/assets/{work-pool-queue-toggle-BAOrV_0R.js.map → work-pool-queue-toggle-CbI7Gfu5.js.map} +1 -1
- prefect/server/ui-v2/assets/{work-pool._workPoolName-BOM3849e.js → work-pool._workPoolName-CCzzgVV2.js} +2 -2
- prefect/server/ui-v2/assets/{work-pool._workPoolName-BOM3849e.js.map → work-pool._workPoolName-CCzzgVV2.js.map} +1 -1
- prefect/server/ui-v2/assets/{work-pool_._workPoolName.edit-CIhcG6yr.js → work-pool_._workPoolName.edit-BAgiuU_j.js} +2 -2
- prefect/server/ui-v2/assets/{work-pool_._workPoolName.edit-CIhcG6yr.js.map → work-pool_._workPoolName.edit-BAgiuU_j.js.map} +1 -1
- prefect/server/ui-v2/assets/{work-pool_._workPoolName.queue._workQueueName-CjoM77tu.js → work-pool_._workPoolName.queue._workQueueName-BUawWJEy.js} +2 -2
- prefect/server/ui-v2/assets/{work-pool_._workPoolName.queue._workQueueName-CjoM77tu.js.map → work-pool_._workPoolName.queue._workQueueName-BUawWJEy.js.map} +1 -1
- prefect/server/ui-v2/assets/{work-queue-icon-text-CP4yX3uM.js → work-queue-icon-text-D_G_UCJX.js} +2 -2
- prefect/server/ui-v2/assets/{work-queue-icon-text-CP4yX3uM.js.map → work-queue-icon-text-D_G_UCJX.js.map} +1 -1
- prefect/server/ui-v2/index.html +2 -2
- prefect/settings/models/flows.py +14 -1
- prefect/settings/models/runner.py +16 -6
- prefect/task_engine.py +1 -3
- prefect/task_worker.py +1 -1
- prefect/tasks.py +2 -2
- prefect/testing/fixtures.py +23 -5
- {prefect-3.6.13.dev2.dist-info → prefect-3.6.14.dev1.dist-info}/METADATA +1 -1
- {prefect-3.6.13.dev2.dist-info → prefect-3.6.14.dev1.dist-info}/RECORD +216 -216
- prefect/server/ui-v2/assets/block-type-logo-WQNm0PzP.js +0 -2
- prefect/server/ui-v2/assets/deployment_._id.duplicate-DB-4hHHc.js +0 -2
- prefect/server/ui-v2/assets/deployment_._id.edit-CWf1RIGy.js +0 -2
- prefect/server/ui-v2/assets/flow-run-graph-DxIl6fzW.js +0 -2
- prefect/server/ui-v2/assets/flow-run-graph-DxIl6fzW.js.map +0 -1
- prefect/server/ui-v2/assets/flow-run._id-DJuMECRh.js +0 -4
- prefect/server/ui-v2/assets/flow-run._id-DJuMECRh.js.map +0 -1
- prefect/server/ui-v2/assets/index-BvSl3DKP.js +0 -17
- prefect/server/ui-v2/assets/index-BvSl3DKP.js.map +0 -1
- prefect/server/ui-v2/assets/index-NY089eTx.css +0 -1
- {prefect-3.6.13.dev2.dist-info → prefect-3.6.14.dev1.dist-info}/WHEEL +0 -0
- {prefect-3.6.13.dev2.dist-info → prefect-3.6.14.dev1.dist-info}/entry_points.txt +0 -0
- {prefect-3.6.13.dev2.dist-info → prefect-3.6.14.dev1.dist-info}/licenses/LICENSE +0 -0
prefect/_build_info.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Generated by versioningit
|
|
2
|
-
__version__ = "3.6.
|
|
3
|
-
__build_date__ = "2026-01-
|
|
4
|
-
__git_commit__ = "
|
|
2
|
+
__version__ = "3.6.14.dev1"
|
|
3
|
+
__build_date__ = "2026-01-23 08:12:06.479550+00:00"
|
|
4
|
+
__git_commit__ = "61276aac1e484a94f570b66a73d5dd6b3eeee5ea"
|
|
5
5
|
__dirty__ = False
|
|
@@ -4,6 +4,24 @@ from typing import Any, Union
|
|
|
4
4
|
from prefect.filesystems import NullFileSystem, WritableFileSystem
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
def call_explicitly_sync_block_method(
|
|
8
|
+
block: Union[WritableFileSystem, NullFileSystem],
|
|
9
|
+
method: str,
|
|
10
|
+
args: tuple[Any, ...],
|
|
11
|
+
kwargs: dict[str, Any],
|
|
12
|
+
) -> Any:
|
|
13
|
+
"""
|
|
14
|
+
Call a block method synchronously.
|
|
15
|
+
|
|
16
|
+
TODO: remove this once we have explicit sync/async methods on all storage blocks
|
|
17
|
+
|
|
18
|
+
see https://github.com/PrefectHQ/prefect/issues/15008
|
|
19
|
+
"""
|
|
20
|
+
# Pass _sync=True to ensure we get synchronous execution even when called
|
|
21
|
+
# from an async context (e.g., within a sync flow running in an async test)
|
|
22
|
+
return getattr(block, method)(*args, _sync=True, **kwargs)
|
|
23
|
+
|
|
24
|
+
|
|
7
25
|
async def call_explicitly_async_block_method(
|
|
8
26
|
block: Union[WritableFileSystem, NullFileSystem],
|
|
9
27
|
method: str,
|
|
@@ -281,6 +281,27 @@ class FlowRunFilterIdempotencyKey(PrefectBaseModel):
|
|
|
281
281
|
)
|
|
282
282
|
|
|
283
283
|
|
|
284
|
+
class FlowRunFilterCreatedBy(PrefectBaseModel, OperatorMixin):
|
|
285
|
+
"""Filter by `FlowRun.created_by`."""
|
|
286
|
+
|
|
287
|
+
id_: Optional[List[UUID]] = Field(
|
|
288
|
+
default=None,
|
|
289
|
+
description="A list of creator IDs to include",
|
|
290
|
+
)
|
|
291
|
+
type_: Optional[List[str]] = Field(
|
|
292
|
+
default=None,
|
|
293
|
+
description=(
|
|
294
|
+
"A list of creator types to include. For example, 'DEPLOYMENT' for "
|
|
295
|
+
"scheduled runs or 'AUTOMATION' for runs triggered by automations."
|
|
296
|
+
),
|
|
297
|
+
examples=[["DEPLOYMENT", "AUTOMATION"]],
|
|
298
|
+
)
|
|
299
|
+
is_null_: Optional[bool] = Field(
|
|
300
|
+
default=None,
|
|
301
|
+
description="If true, only include flow runs without a creator",
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
|
|
284
305
|
class FlowRunFilter(PrefectBaseModel, OperatorMixin):
|
|
285
306
|
"""Filter flow runs. Only flow runs matching all criteria will be returned"""
|
|
286
307
|
|
|
@@ -324,6 +345,9 @@ class FlowRunFilter(PrefectBaseModel, OperatorMixin):
|
|
|
324
345
|
idempotency_key: Optional[FlowRunFilterIdempotencyKey] = Field(
|
|
325
346
|
default=None, description="Filter criteria for `FlowRun.idempotency_key`"
|
|
326
347
|
)
|
|
348
|
+
created_by: Optional[FlowRunFilterCreatedBy] = Field(
|
|
349
|
+
default=None, description="Filter criteria for `FlowRun.created_by`"
|
|
350
|
+
)
|
|
327
351
|
|
|
328
352
|
|
|
329
353
|
class TaskRunFilterFlowRunId(PrefectBaseModel):
|
prefect/flow_engine.py
CHANGED
|
@@ -5,6 +5,7 @@ import logging
|
|
|
5
5
|
import multiprocessing
|
|
6
6
|
import multiprocessing.context
|
|
7
7
|
import os
|
|
8
|
+
import threading
|
|
8
9
|
import time
|
|
9
10
|
from contextlib import (
|
|
10
11
|
AsyncExitStack,
|
|
@@ -36,7 +37,7 @@ from anyio import CancelScope
|
|
|
36
37
|
from opentelemetry import propagate, trace
|
|
37
38
|
from typing_extensions import ParamSpec
|
|
38
39
|
|
|
39
|
-
from prefect import Task
|
|
40
|
+
from prefect import Task, __version__
|
|
40
41
|
from prefect.client.orchestration import PrefectClient, SyncPrefectClient, get_client
|
|
41
42
|
from prefect.client.schemas import FlowRun, TaskRun
|
|
42
43
|
from prefect.client.schemas.filters import FlowRunFilter
|
|
@@ -60,6 +61,8 @@ from prefect.context import (
|
|
|
60
61
|
serialize_context,
|
|
61
62
|
)
|
|
62
63
|
from prefect.engine import handle_engine_signals
|
|
64
|
+
from prefect.events.related import RelatedResource, tags_as_related_resources
|
|
65
|
+
from prefect.events.utilities import emit_event
|
|
63
66
|
from prefect.exceptions import (
|
|
64
67
|
Abort,
|
|
65
68
|
MissingFlowError,
|
|
@@ -161,6 +164,129 @@ def load_flow_and_flow_run(flow_run_id: UUID) -> tuple[FlowRun, Flow[..., Any]]:
|
|
|
161
164
|
return flow_run, flow
|
|
162
165
|
|
|
163
166
|
|
|
167
|
+
@contextmanager
|
|
168
|
+
def send_heartbeats_sync(
|
|
169
|
+
engine: "FlowRunEngine[Any, Any]",
|
|
170
|
+
) -> Generator[None, None, None]:
|
|
171
|
+
"""Context manager that maintains heartbeats for a sync flow run.
|
|
172
|
+
|
|
173
|
+
Heartbeats are emitted at regular intervals while the flow is running.
|
|
174
|
+
The loop checks the flow run state before each heartbeat and stops
|
|
175
|
+
if the run reaches a terminal state.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
engine: The FlowRunEngine instance to emit heartbeats for.
|
|
179
|
+
|
|
180
|
+
Yields:
|
|
181
|
+
None
|
|
182
|
+
"""
|
|
183
|
+
heartbeat_seconds = engine.heartbeat_seconds
|
|
184
|
+
if heartbeat_seconds is None:
|
|
185
|
+
yield
|
|
186
|
+
return
|
|
187
|
+
|
|
188
|
+
stop_event = threading.Event()
|
|
189
|
+
|
|
190
|
+
def heartbeat_loop() -> None:
|
|
191
|
+
while not stop_event.is_set():
|
|
192
|
+
# Check state before emitting - don't emit if final
|
|
193
|
+
if (
|
|
194
|
+
engine.flow_run
|
|
195
|
+
and engine.flow_run.state
|
|
196
|
+
and engine.flow_run.state.is_final()
|
|
197
|
+
):
|
|
198
|
+
engine.logger.debug("Flow run in terminal state, stopping heartbeat")
|
|
199
|
+
return
|
|
200
|
+
|
|
201
|
+
try:
|
|
202
|
+
engine._emit_flow_run_heartbeat()
|
|
203
|
+
except Exception:
|
|
204
|
+
engine.logger.debug("Failed to emit heartbeat", exc_info=True)
|
|
205
|
+
|
|
206
|
+
# Sleep in increments to allow quick shutdown
|
|
207
|
+
for _ in range(heartbeat_seconds):
|
|
208
|
+
if stop_event.is_set():
|
|
209
|
+
return
|
|
210
|
+
time.sleep(1)
|
|
211
|
+
|
|
212
|
+
thread = threading.Thread(target=heartbeat_loop, daemon=True)
|
|
213
|
+
thread.start()
|
|
214
|
+
engine.logger.debug("Started flow run heartbeat context")
|
|
215
|
+
|
|
216
|
+
try:
|
|
217
|
+
yield
|
|
218
|
+
finally:
|
|
219
|
+
stop_event.set()
|
|
220
|
+
thread.join(timeout=2)
|
|
221
|
+
engine.logger.debug("Stopped flow run heartbeat context")
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
@asynccontextmanager
|
|
225
|
+
async def send_heartbeats_async(
|
|
226
|
+
engine: "AsyncFlowRunEngine[Any, Any]",
|
|
227
|
+
) -> AsyncGenerator[None, None]:
|
|
228
|
+
"""Async context manager that maintains heartbeats for an async flow run.
|
|
229
|
+
|
|
230
|
+
Heartbeats are emitted at regular intervals while the flow is running.
|
|
231
|
+
The loop checks the flow run state before each heartbeat and stops
|
|
232
|
+
if the run reaches a terminal state.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
engine: The AsyncFlowRunEngine instance to emit heartbeats for.
|
|
236
|
+
|
|
237
|
+
Yields:
|
|
238
|
+
None
|
|
239
|
+
"""
|
|
240
|
+
heartbeat_seconds = engine.heartbeat_seconds
|
|
241
|
+
if heartbeat_seconds is None:
|
|
242
|
+
yield
|
|
243
|
+
return
|
|
244
|
+
|
|
245
|
+
stop_flag = False
|
|
246
|
+
|
|
247
|
+
async def heartbeat_loop() -> None:
|
|
248
|
+
nonlocal stop_flag
|
|
249
|
+
try:
|
|
250
|
+
while not stop_flag:
|
|
251
|
+
# Check state before emitting - don't emit if final
|
|
252
|
+
if (
|
|
253
|
+
engine.flow_run
|
|
254
|
+
and engine.flow_run.state
|
|
255
|
+
and engine.flow_run.state.is_final()
|
|
256
|
+
):
|
|
257
|
+
engine.logger.debug(
|
|
258
|
+
"Flow run in terminal state, stopping heartbeat"
|
|
259
|
+
)
|
|
260
|
+
return
|
|
261
|
+
|
|
262
|
+
try:
|
|
263
|
+
engine._emit_flow_run_heartbeat()
|
|
264
|
+
except Exception:
|
|
265
|
+
engine.logger.debug("Failed to emit heartbeat", exc_info=True)
|
|
266
|
+
|
|
267
|
+
# Sleep in increments to allow quick shutdown (parity with sync version)
|
|
268
|
+
for _ in range(heartbeat_seconds):
|
|
269
|
+
if stop_flag:
|
|
270
|
+
return
|
|
271
|
+
await asyncio.sleep(1)
|
|
272
|
+
except asyncio.CancelledError:
|
|
273
|
+
engine.logger.debug("Heartbeat loop cancelled")
|
|
274
|
+
|
|
275
|
+
task = asyncio.create_task(heartbeat_loop())
|
|
276
|
+
engine.logger.debug("Started flow run heartbeat context")
|
|
277
|
+
|
|
278
|
+
try:
|
|
279
|
+
yield
|
|
280
|
+
finally:
|
|
281
|
+
stop_flag = True
|
|
282
|
+
task.cancel()
|
|
283
|
+
try:
|
|
284
|
+
await task
|
|
285
|
+
except asyncio.CancelledError:
|
|
286
|
+
pass
|
|
287
|
+
engine.logger.debug("Stopped flow run heartbeat context")
|
|
288
|
+
|
|
289
|
+
|
|
164
290
|
@dataclass
|
|
165
291
|
class BaseFlowRunEngine(Generic[P, R]):
|
|
166
292
|
flow: Union[Flow[P, R], Flow[P, Coroutine[Any, Any, R]]]
|
|
@@ -200,10 +326,59 @@ class BaseFlowRunEngine(Generic[P, R]):
|
|
|
200
326
|
return False # TODO: handle this differently?
|
|
201
327
|
return getattr(self, "flow_run").state.is_pending()
|
|
202
328
|
|
|
329
|
+
@property
|
|
330
|
+
def heartbeat_seconds(self) -> Optional[int]:
|
|
331
|
+
"""Get the heartbeat interval from settings."""
|
|
332
|
+
return get_current_settings().flows.heartbeat_frequency
|
|
333
|
+
|
|
203
334
|
def cancel_all_tasks(self) -> None:
|
|
204
335
|
if hasattr(self.flow.task_runner, "cancel_all"):
|
|
205
336
|
self.flow.task_runner.cancel_all() # type: ignore
|
|
206
337
|
|
|
338
|
+
def _emit_flow_run_heartbeat(self) -> None:
|
|
339
|
+
"""Emit a heartbeat event for the current flow run."""
|
|
340
|
+
if not self.flow_run:
|
|
341
|
+
return
|
|
342
|
+
|
|
343
|
+
related: list[RelatedResource] = []
|
|
344
|
+
tags: list[str] = list(self.flow_run.tags or [])
|
|
345
|
+
|
|
346
|
+
# Add flow as related resource using flow_id for consistency with other events
|
|
347
|
+
if self.flow_run.flow_id:
|
|
348
|
+
related.append(
|
|
349
|
+
RelatedResource.model_validate(
|
|
350
|
+
{
|
|
351
|
+
"prefect.resource.id": f"prefect.flow.{self.flow_run.flow_id}",
|
|
352
|
+
"prefect.resource.role": "flow",
|
|
353
|
+
"prefect.resource.name": self.flow.name if self.flow else "",
|
|
354
|
+
}
|
|
355
|
+
)
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
# Add deployment as related resource if available
|
|
359
|
+
# Note: deployment name is not available on flow_run without an API call
|
|
360
|
+
if self.flow_run.deployment_id:
|
|
361
|
+
related.append(
|
|
362
|
+
RelatedResource.model_validate(
|
|
363
|
+
{
|
|
364
|
+
"prefect.resource.id": f"prefect.deployment.{self.flow_run.deployment_id}",
|
|
365
|
+
"prefect.resource.role": "deployment",
|
|
366
|
+
}
|
|
367
|
+
)
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
related += tags_as_related_resources(set(tags))
|
|
371
|
+
|
|
372
|
+
emit_event(
|
|
373
|
+
event="prefect.flow-run.heartbeat",
|
|
374
|
+
resource={
|
|
375
|
+
"prefect.resource.id": f"prefect.flow-run.{self.flow_run.id}",
|
|
376
|
+
"prefect.resource.name": self.flow_run.name or "",
|
|
377
|
+
"prefect.version": __version__,
|
|
378
|
+
},
|
|
379
|
+
related=related,
|
|
380
|
+
)
|
|
381
|
+
|
|
207
382
|
def _update_otel_labels(
|
|
208
383
|
self, span: trace.Span, client: Union[SyncPrefectClient, PrefectClient]
|
|
209
384
|
):
|
|
@@ -343,6 +518,7 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
|
343
518
|
|
|
344
519
|
self._telemetry.update_state(state)
|
|
345
520
|
self.call_hooks(state)
|
|
521
|
+
|
|
346
522
|
return state
|
|
347
523
|
|
|
348
524
|
def result(self, raise_on_failure: bool = True) -> "Union[R, State, None]":
|
|
@@ -791,10 +967,11 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
|
791
967
|
seconds=self.flow.timeout_seconds,
|
|
792
968
|
timeout_exc_type=FlowRunTimeoutError,
|
|
793
969
|
):
|
|
794
|
-
self
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
970
|
+
with send_heartbeats_sync(self):
|
|
971
|
+
self.logger.debug(
|
|
972
|
+
f"Executing flow {self.flow.name!r} for flow run {self.flow_run.name!r}..."
|
|
973
|
+
)
|
|
974
|
+
yield self
|
|
798
975
|
except TimeoutError as exc:
|
|
799
976
|
self.handle_timeout(exc)
|
|
800
977
|
except Exception as exc:
|
|
@@ -930,6 +1107,7 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
|
930
1107
|
|
|
931
1108
|
self._telemetry.update_state(state)
|
|
932
1109
|
await self.call_hooks(state)
|
|
1110
|
+
|
|
933
1111
|
return state
|
|
934
1112
|
|
|
935
1113
|
async def result(self, raise_on_failure: bool = True) -> "Union[R, State, None]":
|
|
@@ -1381,10 +1559,11 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
|
1381
1559
|
seconds=self.flow.timeout_seconds,
|
|
1382
1560
|
timeout_exc_type=FlowRunTimeoutError,
|
|
1383
1561
|
):
|
|
1384
|
-
self
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1562
|
+
async with send_heartbeats_async(self):
|
|
1563
|
+
self.logger.debug(
|
|
1564
|
+
f"Executing flow {self.flow.name!r} for flow run {self.flow_run.name!r}..."
|
|
1565
|
+
)
|
|
1566
|
+
yield self
|
|
1388
1567
|
except TimeoutError as exc:
|
|
1389
1568
|
await self.handle_timeout(exc)
|
|
1390
1569
|
except Exception as exc:
|
|
@@ -1614,6 +1793,7 @@ def run_flow_in_subprocess(
|
|
|
1614
1793
|
parameters: dict[str, Any] | None = None,
|
|
1615
1794
|
wait_for: Iterable[PrefectFuture[Any]] | None = None,
|
|
1616
1795
|
context: dict[str, Any] | None = None,
|
|
1796
|
+
env: dict[str, str] | None = None,
|
|
1617
1797
|
) -> multiprocessing.context.SpawnProcess:
|
|
1618
1798
|
"""
|
|
1619
1799
|
Run a flow in a subprocess.
|
|
@@ -1630,6 +1810,7 @@ def run_flow_in_subprocess(
|
|
|
1630
1810
|
the current context will be used. A serialized context should be provided if
|
|
1631
1811
|
this function is called in a separate memory space from the parent run (e.g.
|
|
1632
1812
|
in a subprocess or on another machine).
|
|
1813
|
+
env: Additional environment variables to set in the subprocess.
|
|
1633
1814
|
|
|
1634
1815
|
Returns:
|
|
1635
1816
|
A multiprocessing.context.SpawnProcess representing the process that is running the flow.
|
|
@@ -1672,7 +1853,8 @@ def run_flow_in_subprocess(
|
|
|
1672
1853
|
| {
|
|
1673
1854
|
# TODO: make this a thing we can pass into the engine
|
|
1674
1855
|
"PREFECT__ENABLE_CANCELLATION_AND_CRASHED_HOOKS": "false",
|
|
1675
|
-
}
|
|
1856
|
+
}
|
|
1857
|
+
| (env or {}),
|
|
1676
1858
|
flow=flow,
|
|
1677
1859
|
flow_run=flow_run,
|
|
1678
1860
|
parameters=parameters,
|
prefect/flows.py
CHANGED
|
@@ -1717,8 +1717,7 @@ class Flow(Generic[P, R]):
|
|
|
1717
1717
|
return_type=return_type,
|
|
1718
1718
|
)
|
|
1719
1719
|
|
|
1720
|
-
|
|
1721
|
-
async def visualize(self, *args: "P.args", **kwargs: "P.kwargs"):
|
|
1720
|
+
async def avisualize(self, *args: "P.args", **kwargs: "P.kwargs") -> None:
|
|
1722
1721
|
"""
|
|
1723
1722
|
Generates a graphviz object representing the current flow. In IPython notebooks,
|
|
1724
1723
|
it's rendered inline, otherwise in a new window as a PNG.
|
|
@@ -1776,6 +1775,66 @@ class Flow(Generic[P, R]):
|
|
|
1776
1775
|
new_exception.__traceback__ = e.__traceback__
|
|
1777
1776
|
raise new_exception
|
|
1778
1777
|
|
|
1778
|
+
@async_dispatch(avisualize)
|
|
1779
|
+
def visualize(self, *args: "P.args", **kwargs: "P.kwargs") -> None:
|
|
1780
|
+
"""
|
|
1781
|
+
Generates a graphviz object representing the current flow. In IPython notebooks,
|
|
1782
|
+
it's rendered inline, otherwise in a new window as a PNG.
|
|
1783
|
+
|
|
1784
|
+
Raises:
|
|
1785
|
+
- ImportError: If `graphviz` isn't installed.
|
|
1786
|
+
- GraphvizExecutableNotFoundError: If the `dot` executable isn't found.
|
|
1787
|
+
- FlowVisualizationError: If the flow can't be visualized for any other reason.
|
|
1788
|
+
"""
|
|
1789
|
+
from prefect.utilities.visualization import (
|
|
1790
|
+
FlowVisualizationError,
|
|
1791
|
+
GraphvizExecutableNotFoundError,
|
|
1792
|
+
GraphvizImportError,
|
|
1793
|
+
TaskVizTracker,
|
|
1794
|
+
VisualizationUnsupportedError,
|
|
1795
|
+
build_task_dependencies,
|
|
1796
|
+
visualize_task_dependencies,
|
|
1797
|
+
)
|
|
1798
|
+
|
|
1799
|
+
if not PREFECT_TESTING_UNIT_TEST_MODE:
|
|
1800
|
+
warnings.warn(
|
|
1801
|
+
"`flow.visualize()` will execute code inside of your flow that is not"
|
|
1802
|
+
" decorated with `@task` or `@flow`."
|
|
1803
|
+
)
|
|
1804
|
+
|
|
1805
|
+
try:
|
|
1806
|
+
with TaskVizTracker() as tracker:
|
|
1807
|
+
if self.isasync:
|
|
1808
|
+
# Run async flow via event loop
|
|
1809
|
+
run_coro_as_sync(self.fn(*args, **kwargs))
|
|
1810
|
+
else:
|
|
1811
|
+
self.fn(*args, **kwargs)
|
|
1812
|
+
|
|
1813
|
+
graph = build_task_dependencies(tracker)
|
|
1814
|
+
|
|
1815
|
+
visualize_task_dependencies(graph, self.name)
|
|
1816
|
+
|
|
1817
|
+
except GraphvizImportError:
|
|
1818
|
+
raise
|
|
1819
|
+
except GraphvizExecutableNotFoundError:
|
|
1820
|
+
raise
|
|
1821
|
+
except VisualizationUnsupportedError:
|
|
1822
|
+
raise
|
|
1823
|
+
except FlowVisualizationError:
|
|
1824
|
+
raise
|
|
1825
|
+
except Exception as e:
|
|
1826
|
+
msg = (
|
|
1827
|
+
"It's possible you are trying to visualize a flow that contains "
|
|
1828
|
+
"code that directly interacts with the result of a task"
|
|
1829
|
+
" inside of the flow. \nTry passing a `viz_return_value` "
|
|
1830
|
+
"to the task decorator, e.g. `@task(viz_return_value=[1, 2, 3]).`"
|
|
1831
|
+
)
|
|
1832
|
+
|
|
1833
|
+
new_exception = type(e)(str(e) + "\n" + msg)
|
|
1834
|
+
# Copy traceback information from the original exception
|
|
1835
|
+
new_exception.__traceback__ = e.__traceback__
|
|
1836
|
+
raise new_exception
|
|
1837
|
+
|
|
1779
1838
|
|
|
1780
1839
|
class FlowDecorator:
|
|
1781
1840
|
@overload
|