writer 0.8.3rc21__py3-none-any.whl → 1.25.1rc1__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.
- writer/ai/__init__.py +277 -28
- writer/app_runner.py +236 -32
- writer/app_templates/default/.wf/components-blueprints_blueprint-0-0decp3w5erhvl0nw.jsonl +11 -0
- writer/app_templates/default/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl +22 -10
- writer/app_templates/default/.wf/components-root.jsonl +1 -1
- writer/app_templates/default/.wf/components-workflows_root.jsonl +1 -0
- writer/app_templates/default/.wf/components-workflows_workflow-0-lfltcky7l1fsm6j2.jsonl +1 -0
- writer/app_templates/default/.wf/metadata.json +1 -1
- writer/app_templates/default/README.md +3 -0
- writer/app_templates/default/main.py +8 -5
- writer/app_templates/default/requirements.txt +1 -0
- writer/app_templates/default/static/agent_builder_demo.png +0 -0
- writer/app_templates/hello/main.py +3 -0
- writer/auth.py +7 -2
- writer/autogen.py +26 -9
- writer/blocks/__init__.py +21 -1
- writer/blocks/addtostatelist.py +5 -4
- writer/blocks/apitrigger.py +45 -0
- writer/blocks/base_block.py +134 -14
- writer/blocks/changepage.py +1 -1
- writer/blocks/code.py +27 -11
- writer/blocks/crontrigger.py +49 -0
- writer/blocks/foreach.py +3 -3
- writer/blocks/httprequest.py +8 -24
- writer/blocks/ifelse.py +71 -0
- writer/blocks/logmessage.py +2 -2
- writer/blocks/returnvalue.py +2 -2
- writer/blocks/runblueprint.py +2 -2
- writer/blocks/setstate.py +5 -5
- writer/blocks/sharedblueprint.py +86 -0
- writer/blocks/writeraddchatmessage.py +45 -7
- writer/blocks/writeraddtokg.py +31 -4
- writer/blocks/writeraskkg.py +27 -34
- writer/blocks/writerchat.py +14 -9
- writer/blocks/writerchatreply.py +279 -0
- writer/blocks/writerchatreplywithtoolconfig.py +393 -0
- writer/blocks/writerclassification.py +42 -5
- writer/blocks/writercompletion.py +4 -4
- writer/blocks/writerfileapi.py +4 -4
- writer/blocks/writerinitchat.py +5 -4
- writer/blocks/writerkeyvaluestorage.py +106 -0
- writer/blocks/writernocodeapp.py +4 -4
- writer/blocks/writerparsepdf.py +8 -6
- writer/blocks/writerstructuredoutput.py +105 -0
- writer/blocks/writertoolcalling.py +106 -51
- writer/blocks/writervision.py +141 -0
- writer/blocks/writerwebsearch.py +175 -0
- writer/blueprints.py +715 -251
- writer/command_line.py +52 -16
- writer/core.py +200 -35
- writer/core_ui.py +4 -0
- writer/evaluator.py +38 -24
- writer/journal.py +227 -0
- writer/keyvalue_storage.py +93 -0
- writer/logs.py +277 -0
- writer/serve.py +402 -198
- writer/ss_types.py +41 -0
- writer/static/assets/BaseMarkdown-Wrvby5J8.js +1 -0
- writer/static/assets/BlueprintToolbar-BuXNRxWT.js +1 -0
- writer/static/assets/BlueprintToolbar-wpfX0jo_.css +1 -0
- writer/static/assets/BuilderApp-PTOI76jZ.js +8 -0
- writer/static/assets/BuilderApp-WimUfNZr.css +1 -0
- writer/static/assets/BuilderApplicationSelect-DXzy4e_h.js +7 -0
- writer/static/assets/BuilderApplicationSelect-XaM1D5fv.css +1 -0
- writer/static/assets/BuilderBlueprintLibraryPanel-Ckrhknlh.css +1 -0
- writer/static/assets/BuilderBlueprintLibraryPanel-DBDzhTlc.js +1 -0
- writer/static/assets/{BuilderEmbeddedCodeEditor-DiDqfWdt.css → BuilderEmbeddedCodeEditor-B0bcjlhk.css} +1 -1
- writer/static/assets/{BuilderEmbeddedCodeEditor-CbK-r9w6.js → BuilderEmbeddedCodeEditor-Dn7eDICN.js} +7 -7
- writer/static/assets/BuilderGraphSelect-C-LRsO8W.js +7 -0
- writer/static/assets/BuilderGraphSelect-D7B61d5s.css +1 -0
- writer/static/assets/{BuilderInsertionLabel-CDlWX-mE.js → BuilderInsertionLabel-BhyL9wgn.js} +1 -1
- writer/static/assets/{BuilderInsertionOverlay-B7-TsHNC.js → BuilderInsertionOverlay-MkAIVruY.js} +1 -1
- writer/static/assets/BuilderJournal-A0LcEwGI.js +7 -0
- writer/static/assets/BuilderJournal-DHv3Pvvm.css +1 -0
- writer/static/assets/BuilderModelSelect-CdSo_sih.js +7 -0
- writer/static/assets/BuilderModelSelect-Dc4IPLp2.css +1 -0
- writer/static/assets/BuilderSettings-BDwZBveu.js +16 -0
- writer/static/assets/BuilderSettings-lZkOXEYw.css +1 -0
- writer/static/assets/BuilderSettingsArtifactAPITriggerDetails-3O6jKBXD.js +4 -0
- writer/static/assets/BuilderSettingsArtifactAPITriggerDetails-DnX66iRg.css +1 -0
- writer/static/assets/BuilderSettingsDeploySharedBlueprint-BR_3ptsd.js +1 -0
- writer/static/assets/BuilderSettingsDeploySharedBlueprint-KJTl8gxP.css +1 -0
- writer/static/assets/BuilderSettingsHandlers-CBtEQFSo.js +1 -0
- writer/static/assets/BuilderSettingsHandlers-DJPeASfz.css +1 -0
- writer/static/assets/BuilderSidebarComponentTree-DLltgas5.js +1 -0
- writer/static/assets/BuilderSidebarComponentTree-DYu1F793.css +1 -0
- writer/static/assets/BuilderSidebarToolkit-CApZNTAq.js +7 -0
- writer/static/assets/BuilderSidebarToolkit-CwqbjRv8.css +1 -0
- writer/static/assets/BuilderTemplateEditor-CYSDeWgV.css +1 -0
- writer/static/assets/BuilderTemplateEditor-DnRDRcA0.js +87 -0
- writer/static/assets/BuilderVault-2vGoV0sx.js +1 -0
- writer/static/assets/BuilderVault-Cx6oQSES.css +1 -0
- writer/static/assets/ComponentRenderer-72hqvEvI.css +1 -0
- writer/static/assets/ComponentRenderer-D4Pj1i3s.js +1 -0
- writer/static/assets/SharedCopyClipboardButton-BipJKGtz.css +1 -0
- writer/static/assets/SharedCopyClipboardButton-DNI9kLe6.js +1 -0
- writer/static/assets/WdsCheckbox-DKvpPA4D.css +1 -0
- writer/static/assets/WdsCheckbox-edQcn1cf.js +1 -0
- writer/static/assets/WdsDropdownMenu-CzzPN9Wg.css +1 -0
- writer/static/assets/WdsDropdownMenu-DQnrRBNV.js +1 -0
- writer/static/assets/WdsFieldWrapper-Cmufx5Nj.js +1 -0
- writer/static/assets/WdsFieldWrapper-CsemOh8D.css +1 -0
- writer/static/assets/WdsTabs-DKj7BqI0.css +1 -0
- writer/static/assets/WdsTabs-DcfY_zn5.js +1 -0
- writer/static/assets/{art-paper-WsD9P5Lu.svg → art-paper-D70v1WMA.svg} +0 -1
- writer/static/assets/{cssMode-6B7VrieQ.js → cssMode-BYq4oZGq.js} +1 -1
- writer/static/assets/{freemarker2-Dy54TNCQ.js → freemarker2-CnNourkO.js} +1 -1
- writer/static/assets/{handlebars-BnWqX2x5.js → handlebars-Bm22yapJ.js} +1 -1
- writer/static/assets/{html-CIuj_eOg.js → html-CAKAfoZF.js} +1 -1
- writer/static/assets/{htmlMode-5fUQN2xJ.js → htmlMode-BGZ97n-V.js} +1 -1
- writer/static/assets/index-BKNuk68o.css +1 -0
- writer/static/assets/index-BQNXU3IR.js +17 -0
- writer/static/assets/index-DHXAd5Yn.js +4 -0
- writer/static/assets/index-Zki-pfO-.js +8525 -0
- writer/static/assets/index.esm-B1ZQtduY.js +17 -0
- writer/static/assets/{javascript-PLzaI1wY.js → javascript-X1f02eyK.js} +1 -1
- writer/static/assets/{jsonMode-CzZfZ4-D.js → jsonMode-hT0bNgT8.js} +1 -1
- writer/static/assets/{liquid-Cy21vWLb.js → liquid-KmCCiJw2.js} +1 -1
- writer/static/assets/{mapbox-gl-BjXsUCYi.js → mapbox-gl-C0cyFYYW.js} +1 -1
- writer/static/assets/{mdx-Cgik3q5p.js → mdx-DtRFauUw.js} +1 -1
- writer/static/assets/pdf-B6-yWJ-Y.js +12 -0
- writer/static/assets/pdf.worker.min-CyUfim15.mjs +21 -0
- writer/static/assets/{plotly.min-Dk-1ahEu.js → plotly.min-DutuuatZ.js} +1 -1
- writer/static/assets/{python-h6gjz_bN.js → python-DVhxg746.js} +1 -1
- writer/static/assets/{razor-BQ1k9241.js → razor-DR5Ns_BC.js} +1 -1
- writer/static/assets/{tsMode-BaBWt05D.js → tsMode-BNUEZzir.js} +1 -1
- writer/static/assets/{typescript-B42-gYGT.js → typescript-CRVt7Hx0.js} +1 -1
- writer/static/assets/useBlueprintRun-C00bCxh-.js +1 -0
- writer/static/assets/useKeyValueEditor-nDmI7cTJ.js +1 -0
- writer/static/assets/useListResources-DLkZhRSJ.js +1 -0
- writer/static/assets/{xml-BOez4Prd.js → xml-C_6-t1tb.js} +1 -1
- writer/static/assets/{yaml-BQhoEOIz.js → yaml-DIw8G7jk.js} +1 -1
- writer/static/components/annotatedtext.svg +3 -3
- writer/static/components/avatar.svg +3 -3
- writer/static/components/blueprints_addtostatelist.svg +3 -3
- writer/static/components/blueprints_apitrigger.svg +4 -0
- writer/static/components/blueprints_category_Logic.svg +3 -3
- writer/static/components/blueprints_category_Other.svg +3 -3
- writer/static/components/blueprints_category_Writer.svg +24 -5
- writer/static/components/blueprints_code.svg +6 -6
- writer/static/components/blueprints_crontrigger.svg +6 -0
- writer/static/components/blueprints_foreach.svg +3 -3
- writer/static/components/blueprints_httprequest.svg +6 -6
- writer/static/components/blueprints_logmessage.svg +10 -3
- writer/static/components/blueprints_parsejson.svg +3 -3
- writer/static/components/blueprints_returnvalue.svg +3 -3
- writer/static/components/blueprints_runblueprint.svg +3 -3
- writer/static/components/blueprints_setstate.svg +3 -3
- writer/static/components/blueprints_writeraddchatmessage.svg +14 -6
- writer/static/components/blueprints_writeraddtokg.svg +14 -6
- writer/static/components/blueprints_writerchatreply.svg +19 -0
- writer/static/components/blueprints_writerclassification.svg +23 -8
- writer/static/components/blueprints_writercompletion.svg +13 -5
- writer/static/components/blueprints_writernocodeapp.svg +13 -3
- writer/static/components/button.svg +3 -3
- writer/static/components/category_Content.svg +3 -3
- writer/static/components/category_Embed.svg +3 -3
- writer/static/components/category_Input.svg +4 -4
- writer/static/components/category_Layout.svg +6 -6
- writer/static/components/category_Other.svg +3 -3
- writer/static/components/chatbot.svg +3 -3
- writer/static/components/checkboxinput.svg +3 -3
- writer/static/components/colorinput.svg +6 -6
- writer/static/components/column.svg +3 -3
- writer/static/components/columns.svg +3 -3
- writer/static/components/dataframe.svg +3 -3
- writer/static/components/dateinput.svg +3 -3
- writer/static/components/dropdowninput.svg +4 -4
- writer/static/components/fileinput.svg +3 -3
- writer/static/components/googlemaps.svg +3 -3
- writer/static/components/heading.svg +6 -6
- writer/static/components/horizontalstack.svg +3 -3
- writer/static/components/html.svg +6 -6
- writer/static/components/icon.svg +3 -3
- writer/static/components/iframe.svg +3 -3
- writer/static/components/image.svg +10 -3
- writer/static/components/jsonviewer.svg +3 -3
- writer/static/components/link.svg +7 -7
- writer/static/components/mapbox.svg +3 -3
- writer/static/components/message.svg +3 -3
- writer/static/components/metric.svg +3 -3
- writer/static/components/multiselectinput.svg +3 -3
- writer/static/components/numberinput.svg +3 -3
- writer/static/components/pagination.svg +3 -3
- writer/static/components/pdf.svg +3 -3
- writer/static/components/plotlygraph.svg +6 -6
- writer/static/components/progressbar.svg +4 -4
- writer/static/components/radioinput.svg +3 -3
- writer/static/components/rangeinput.svg +3 -3
- writer/static/components/ratinginput.svg +3 -3
- writer/static/components/repeater.svg +3 -3
- writer/static/components/reuse.svg +3 -3
- writer/static/components/section.svg +3 -3
- writer/static/components/selectinput.svg +4 -4
- writer/static/components/separator.svg +3 -3
- writer/static/components/sidebar.svg +3 -3
- writer/static/components/sliderinput.svg +3 -3
- writer/static/components/step.svg +3 -3
- writer/static/components/steps.svg +3 -3
- writer/static/components/switchinput.svg +3 -3
- writer/static/components/tab.svg +3 -3
- writer/static/components/tabs.svg +3 -3
- writer/static/components/tags.svg +10 -3
- writer/static/components/text.svg +3 -3
- writer/static/components/textareainput.svg +10 -3
- writer/static/components/textinput.svg +3 -3
- writer/static/components/timeinput.svg +3 -3
- writer/static/components/timer.svg +3 -3
- writer/static/components/videoplayer.svg +10 -3
- writer/static/components/webcamcapture.svg +3 -3
- writer/static/index.html +3 -11
- writer/static/status/cancelled.svg +5 -0
- writer/static/status/skipped.svg +4 -0
- writer/static/status/stopped.svg +4 -0
- writer/sync.py +431 -0
- writer/ui.py +49 -41
- writer/vault.py +48 -0
- writer/wf_project.py +5 -5
- writer-1.25.1rc1.dist-info/METADATA +92 -0
- writer-1.25.1rc1.dist-info/RECORD +382 -0
- {writer-0.8.3rc21.dist-info → writer-1.25.1rc1.dist-info}/WHEEL +1 -1
- writer/app_templates/default/.wf/components-blueprints_blueprint-0-t84xyhxau9ej3823.jsonl +0 -18
- writer/app_templates/default/static/welcome.svg +0 -40
- writer/static/assets/BaseMarkdown-BH_nSq9H.js +0 -1
- writer/static/assets/BlueprintToolbar-BO-WERxH.css +0 -1
- writer/static/assets/BlueprintToolbar-CHWL-rTm.js +0 -1
- writer/static/assets/BuilderApp-0XXiQ2l7.js +0 -7
- writer/static/assets/BuilderApp-CAhvLO4a.css +0 -1
- writer/static/assets/BuilderApplicationSelect-CwzU4F1-.js +0 -7
- writer/static/assets/BuilderApplicationSelect-DYYFtqjx.css +0 -1
- writer/static/assets/BuilderGraphSelect-CVO4gzts.css +0 -1
- writer/static/assets/BuilderGraphSelect-DV5Xy0HK.js +0 -7
- writer/static/assets/BuilderInstanceTracker-BECcXNnW.css +0 -1
- writer/static/assets/BuilderInstanceTracker-Dr0XhpSH.js +0 -1
- writer/static/assets/BuilderModelSelect-QHUGd86u.css +0 -1
- writer/static/assets/BuilderModelSelect-ow0XEf2t.js +0 -7
- writer/static/assets/BuilderSettings-C2WRfSor.css +0 -1
- writer/static/assets/BuilderSettings-D5bjbcWj.js +0 -24
- writer/static/assets/BuilderSettingsHandlers-1QLaHR8J.css +0 -1
- writer/static/assets/BuilderSettingsHandlers-j1aMAV4J.js +0 -1
- writer/static/assets/BuilderSidebarComponentTree-0YajaJke.css +0 -1
- writer/static/assets/BuilderSidebarComponentTree-CtaOZfpV.js +0 -1
- writer/static/assets/BuilderSidebarPanel-BMJVzhd3.js +0 -1
- writer/static/assets/BuilderSidebarPanel-BrLsNxVM.css +0 -1
- writer/static/assets/BuilderSidebarToolkit-BbjOOp8E.js +0 -1
- writer/static/assets/BuilderSidebarToolkit-BvZDShKD.css +0 -1
- writer/static/assets/ComponentRenderer-B76bKRZO.css +0 -1
- writer/static/assets/ComponentRenderer-CZs4z773.js +0 -1
- writer/static/assets/SharedMoreDropdown-BWKlox8E.css +0 -1
- writer/static/assets/SharedMoreDropdown-DKv_HNef.js +0 -7
- writer/static/assets/WdsDropdownMenu-C1UyKOJR.css +0 -1
- writer/static/assets/WdsDropdownMenu-CGiATY2E.js +0 -1
- writer/static/assets/WdsLoaderDots-qdyk2N-2.js +0 -1
- writer/static/assets/index-BJMAe9SN.js +0 -8
- writer/static/assets/index-CPCeQU9V.css +0 -1
- writer/static/assets/index-ChWW_c_j.js +0 -439
- writer/static/assets/instancePath-BsbOTTI8.js +0 -1
- writer/static/assets/material-symbols-outlined-latin-wght-normal-DuE-q1Ez.woff2 +0 -0
- writer/static/assets/useBlueprintRun-CBOvzWTA.js +0 -1
- writer/static/assets/useComponentDescription-FHKxu8gg.js +0 -1
- writer/static/assets/useListResources-BpMgq7XI.js +0 -1
- writer-0.8.3rc21.dist-info/METADATA +0 -117
- writer-0.8.3rc21.dist-info/RECORD +0 -342
- {writer-0.8.3rc21.dist-info → writer-1.25.1rc1.dist-info}/entry_points.txt +0 -0
- {writer-0.8.3rc21.dist-info → writer-1.25.1rc1.dist-info/licenses}/LICENSE.txt +0 -0
writer/command_line.py
CHANGED
|
@@ -7,6 +7,7 @@ import click
|
|
|
7
7
|
import writer.serve
|
|
8
8
|
from writer import VERSION, wf_project
|
|
9
9
|
from writer.deploy import cloud, deploy
|
|
10
|
+
from writer.sync import FileBuffering
|
|
10
11
|
|
|
11
12
|
CONTEXT_SETTINGS = {'help_option_names': ['-h', '--help']}
|
|
12
13
|
@click.group(
|
|
@@ -20,9 +21,8 @@ def main():
|
|
|
20
21
|
@main.command()
|
|
21
22
|
@click.option('--host', default="127.0.0.1", help="Host to run the app on")
|
|
22
23
|
@click.option('--port', default=None, help="Port to run the app on")
|
|
23
|
-
@click.option("--enable-jobs-api", help="Set this flag to enable the Jobs API, allowing you to execute jobs without user interaction.", is_flag=True)
|
|
24
24
|
@click.argument('path')
|
|
25
|
-
def run(path: str, host: str, port: Optional[int]
|
|
25
|
+
def run(path: str, host: str, port: Optional[int]):
|
|
26
26
|
"""Run the app from PATH folder in run mode."""
|
|
27
27
|
|
|
28
28
|
abs_path = os.path.abspath(path)
|
|
@@ -35,15 +35,23 @@ def run(path: str, host: str, port: Optional[int], enable_jobs_api: bool):
|
|
|
35
35
|
raise click.ClickException(f"There's no Writer Framework project at this location : {abs_path}")
|
|
36
36
|
|
|
37
37
|
writer.serve.serve(
|
|
38
|
-
abs_path,
|
|
38
|
+
abs_path,
|
|
39
|
+
mode="run",
|
|
40
|
+
port=port,
|
|
41
|
+
host=host,
|
|
42
|
+
enable_server_setup=True
|
|
43
|
+
)
|
|
39
44
|
|
|
40
45
|
@main.command()
|
|
41
46
|
@click.option('--host', default="127.0.0.1", help="Host to run the app on")
|
|
42
47
|
@click.option('--port', default=None, help="Port to run the app on")
|
|
43
48
|
@click.option('--enable-remote-edit', help="Set this flag to allow non-local requests in edit mode.", is_flag=True)
|
|
44
49
|
@click.option('--enable-server-setup', help="Set this flag to enable server setup hook in edit mode.", is_flag=True)
|
|
50
|
+
@click.option('--enable-file-buffering', help="Set this flag to enable file buffering in edit mode.", is_flag=True)
|
|
51
|
+
@click.option('--buffer-sync-interval', default=10, type=int, help="Interval in seconds for synchronizing the file buffer.")
|
|
52
|
+
@click.option('--buffer-path', default=None, type=str, help="Path to the file buffer directory. If not provided, a temporary directory will be used.")
|
|
45
53
|
@click.option("--no-interactive", help="Set this flag to run the app without asking anything to the user.", is_flag=True)
|
|
46
|
-
@click.option(
|
|
54
|
+
@click.option('--verbose', '-v', is_flag=True, help="Enable verbose output.")
|
|
47
55
|
@click.argument('path')
|
|
48
56
|
def edit(
|
|
49
57
|
path: str,
|
|
@@ -51,28 +59,56 @@ def edit(
|
|
|
51
59
|
host: str,
|
|
52
60
|
enable_remote_edit: bool,
|
|
53
61
|
enable_server_setup: bool,
|
|
62
|
+
enable_file_buffering: bool,
|
|
63
|
+
buffer_sync_interval: int,
|
|
64
|
+
buffer_path: Optional[str],
|
|
54
65
|
no_interactive: bool,
|
|
55
|
-
|
|
66
|
+
verbose: bool = False
|
|
56
67
|
):
|
|
57
68
|
"""Run the app from PATH folder in edit mode."""
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
buffer = None
|
|
70
|
+
|
|
71
|
+
if enable_file_buffering:
|
|
72
|
+
buffer = FileBuffering(
|
|
73
|
+
dest_dir=path,
|
|
74
|
+
src_dir=os.path.abspath(buffer_path) if buffer_path else None,
|
|
75
|
+
verbose=verbose,
|
|
76
|
+
interval=buffer_sync_interval,
|
|
77
|
+
)
|
|
78
|
+
print(f"Using temporary buffer path: {buffer.path}")
|
|
79
|
+
buffer.init()
|
|
80
|
+
buffer.watch_changes()
|
|
81
|
+
print("File buffering started in background")
|
|
82
|
+
|
|
83
|
+
project_path = buffer.path
|
|
84
|
+
else:
|
|
85
|
+
project_path = path
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
abs_path = os.path.abspath(project_path)
|
|
89
|
+
if wf_project.is_project(project_path) is False and \
|
|
90
|
+
wf_project.can_create_project(project_path) is True and \
|
|
61
91
|
no_interactive is False:
|
|
62
92
|
click.confirm("There’s no Writer Framework project at this location, would you like to create a new one ?", default=False, abort=True)
|
|
63
|
-
create_app(
|
|
93
|
+
create_app(project_path, template_name="default", overwrite=False)
|
|
64
94
|
|
|
65
|
-
if wf_project.is_project(
|
|
66
|
-
wf_project.can_create_project(
|
|
95
|
+
if wf_project.is_project(project_path) is False and \
|
|
96
|
+
wf_project.can_create_project(project_path) is True:
|
|
67
97
|
raise click.ClickException(f"There’s no Writer Framework project at this location, create a new one with `writer create {path}`")
|
|
68
98
|
|
|
69
|
-
if wf_project.is_project(
|
|
70
|
-
wf_project.can_create_project(
|
|
99
|
+
if wf_project.is_project(project_path) is False and \
|
|
100
|
+
wf_project.can_create_project(project_path) is False:
|
|
71
101
|
raise click.ClickException(f"There’s no Writer Framework project at this location : {abs_path}")
|
|
72
102
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
103
|
+
try:
|
|
104
|
+
writer.serve.serve(
|
|
105
|
+
abs_path, mode="edit", port=port, host=host,
|
|
106
|
+
enable_remote_edit=enable_remote_edit, enable_server_setup=enable_server_setup,
|
|
107
|
+
)
|
|
108
|
+
finally:
|
|
109
|
+
if buffer:
|
|
110
|
+
print("Stopping file buffering...")
|
|
111
|
+
buffer.stop()
|
|
76
112
|
|
|
77
113
|
@main.command()
|
|
78
114
|
@click.argument('path')
|
writer/core.py
CHANGED
|
@@ -46,7 +46,9 @@ import writer.blocks
|
|
|
46
46
|
import writer.evaluator
|
|
47
47
|
from writer import core_ui
|
|
48
48
|
from writer.core_ui import Component
|
|
49
|
+
from writer.logs import use_stdout_redirect
|
|
49
50
|
from writer.ss_types import (
|
|
51
|
+
BlueprintExecutionError,
|
|
50
52
|
BlueprintExecutionLog,
|
|
51
53
|
InstancePath,
|
|
52
54
|
Readable,
|
|
@@ -55,11 +57,13 @@ from writer.ss_types import (
|
|
|
55
57
|
WriterEventResult,
|
|
56
58
|
WriterFileItem,
|
|
57
59
|
)
|
|
60
|
+
from writer.vault import writer_vault
|
|
58
61
|
|
|
59
62
|
if TYPE_CHECKING:
|
|
60
63
|
import pandas
|
|
61
64
|
|
|
62
65
|
from writer.app_runner import AppProcess
|
|
66
|
+
from writer.blueprints import BlueprintRunner
|
|
63
67
|
from writer.ss_types import AppProcessServerRequest
|
|
64
68
|
|
|
65
69
|
|
|
@@ -157,6 +161,7 @@ class WriterSession:
|
|
|
157
161
|
self.session_component_tree = core_ui.build_session_component_tree(base_component_tree)
|
|
158
162
|
self.event_handler = EventHandler(self)
|
|
159
163
|
self.userinfo: Optional[dict] = None
|
|
164
|
+
self.queued_messages: List[Any] = []
|
|
160
165
|
|
|
161
166
|
def update_last_active_timestamp(self) -> None:
|
|
162
167
|
self.last_active_timestamp = int(time.time())
|
|
@@ -798,7 +803,7 @@ class State(metaclass=StateMeta):
|
|
|
798
803
|
If there is a StateProxy, it is a fault in the code.
|
|
799
804
|
"""
|
|
800
805
|
annotations = get_annotations(self)
|
|
801
|
-
expected_type = annotations.get(key, None)
|
|
806
|
+
expected_type = cast(Type, annotations.get(key, None))
|
|
802
807
|
expect_dict = _type_match_dict(expected_type)
|
|
803
808
|
if isinstance(value, dict) and not expect_dict:
|
|
804
809
|
"""
|
|
@@ -1077,6 +1082,10 @@ class WriterState(State):
|
|
|
1077
1082
|
shortened_message = message[0 : WriterState.LOG_ENTRY_MAX_LEN] + "..."
|
|
1078
1083
|
else:
|
|
1079
1084
|
shortened_message = message
|
|
1085
|
+
|
|
1086
|
+
if id is not None:
|
|
1087
|
+
self._remove_duplicates_in_mail(id)
|
|
1088
|
+
|
|
1080
1089
|
self.add_mail(
|
|
1081
1090
|
"logEntry",
|
|
1082
1091
|
{
|
|
@@ -1104,6 +1113,18 @@ class WriterState(State):
|
|
|
1104
1113
|
def clear_mail(self) -> None:
|
|
1105
1114
|
self.mail = []
|
|
1106
1115
|
|
|
1116
|
+
def _remove_duplicates_in_mail(self, id: str) -> None:
|
|
1117
|
+
new_mail = []
|
|
1118
|
+
for entry in self.mail:
|
|
1119
|
+
if entry["type"] != "logEntry":
|
|
1120
|
+
new_mail.append(entry)
|
|
1121
|
+
continue
|
|
1122
|
+
log_id = entry["payload"].get("id")
|
|
1123
|
+
if log_id != id:
|
|
1124
|
+
new_mail.append(entry)
|
|
1125
|
+
continue
|
|
1126
|
+
self.mail = new_mail
|
|
1127
|
+
|
|
1107
1128
|
def set_page(self, active_page_key: str) -> None:
|
|
1108
1129
|
self.add_mail("pageChange", active_page_key)
|
|
1109
1130
|
|
|
@@ -1201,8 +1222,136 @@ class EventHandlerRegistry:
|
|
|
1201
1222
|
callable: Callable
|
|
1202
1223
|
meta: "EventHandlerRegistry.HandlerMeta"
|
|
1203
1224
|
|
|
1225
|
+
# === BLUEPRINT HANLDERS ===
|
|
1226
|
+
@staticmethod
|
|
1227
|
+
def stop_blueprint_run(payload: dict, blueprint_runner: "BlueprintRunner"):
|
|
1228
|
+
run_id = payload.pop("run_id", None)
|
|
1229
|
+
if not run_id:
|
|
1230
|
+
raise ValueError("Missing run_id in payload")
|
|
1231
|
+
return blueprint_runner.cancel_blueprint_execution(run_id=run_id)
|
|
1232
|
+
|
|
1233
|
+
@staticmethod
|
|
1234
|
+
def run_blueprint_by_id(
|
|
1235
|
+
payload: dict,
|
|
1236
|
+
context: dict,
|
|
1237
|
+
session: dict,
|
|
1238
|
+
blueprint_runner: "BlueprintRunner",
|
|
1239
|
+
vault: Dict,
|
|
1240
|
+
):
|
|
1241
|
+
blueprint_id = payload.pop("blueprint_id", None)
|
|
1242
|
+
if not blueprint_id:
|
|
1243
|
+
raise ValueError("Missing blueprint_id in payload")
|
|
1244
|
+
execution_environment = EventHandler._get_blueprint_execution_environment(
|
|
1245
|
+
payload, context, session, vault
|
|
1246
|
+
)
|
|
1247
|
+
return blueprint_runner.run_blueprint(
|
|
1248
|
+
component_id=blueprint_id,
|
|
1249
|
+
execution_environment=execution_environment,
|
|
1250
|
+
title="Blueprint execution triggered on demand",
|
|
1251
|
+
)
|
|
1252
|
+
|
|
1253
|
+
@staticmethod
|
|
1254
|
+
def run_blueprint_by_key(
|
|
1255
|
+
payload: dict,
|
|
1256
|
+
context: dict,
|
|
1257
|
+
session: dict,
|
|
1258
|
+
blueprint_runner: "BlueprintRunner",
|
|
1259
|
+
vault: Dict,
|
|
1260
|
+
):
|
|
1261
|
+
blueprint_key = payload.pop("blueprint_key", None)
|
|
1262
|
+
if not blueprint_key:
|
|
1263
|
+
raise ValueError("Missing blueprint_key in payload")
|
|
1264
|
+
execution_environment = EventHandler._get_blueprint_execution_environment(
|
|
1265
|
+
payload, context, session, vault
|
|
1266
|
+
)
|
|
1267
|
+
return blueprint_runner.run_blueprint_by_key(
|
|
1268
|
+
blueprint_key=blueprint_key, execution_environment=execution_environment
|
|
1269
|
+
)
|
|
1270
|
+
|
|
1271
|
+
@staticmethod
|
|
1272
|
+
def run_blueprint_via_api(
|
|
1273
|
+
payload: dict,
|
|
1274
|
+
context: dict,
|
|
1275
|
+
session: dict,
|
|
1276
|
+
blueprint_runner: "BlueprintRunner",
|
|
1277
|
+
vault: Dict,
|
|
1278
|
+
):
|
|
1279
|
+
"""
|
|
1280
|
+
This handler is used to run a blueprint via the API.
|
|
1281
|
+
It is used by the frontend to run a blueprint when the user clicks on a button.
|
|
1282
|
+
"""
|
|
1283
|
+
blueprint_id = payload.pop("blueprint_id", None)
|
|
1284
|
+
if not blueprint_id:
|
|
1285
|
+
raise ValueError("Missing blueprint_id in payload")
|
|
1286
|
+
trigger_type = payload.pop("trigger_type", None)
|
|
1287
|
+
if not trigger_type:
|
|
1288
|
+
raise ValueError("Missing trigger_type in payload")
|
|
1289
|
+
execution_environment = EventHandler._get_blueprint_execution_environment(
|
|
1290
|
+
payload, context, session, vault
|
|
1291
|
+
)
|
|
1292
|
+
return blueprint_runner.run_blueprint_via_api(
|
|
1293
|
+
blueprint_id=blueprint_id,
|
|
1294
|
+
trigger_type=trigger_type,
|
|
1295
|
+
branch_id=payload.pop("branch_id", None),
|
|
1296
|
+
execution_environment=execution_environment,
|
|
1297
|
+
)
|
|
1298
|
+
|
|
1299
|
+
@staticmethod
|
|
1300
|
+
def run_blueprint_branch(
|
|
1301
|
+
payload: dict,
|
|
1302
|
+
context: dict,
|
|
1303
|
+
session: dict,
|
|
1304
|
+
blueprint_runner: "BlueprintRunner",
|
|
1305
|
+
vault: Dict,
|
|
1306
|
+
):
|
|
1307
|
+
branch_id = payload.pop("branch_id", None)
|
|
1308
|
+
if not branch_id:
|
|
1309
|
+
raise ValueError("Missing branch_id in payload")
|
|
1310
|
+
execution_environment = EventHandler._get_blueprint_execution_environment(
|
|
1311
|
+
payload, context, session, vault
|
|
1312
|
+
)
|
|
1313
|
+
return blueprint_runner.run_branch(
|
|
1314
|
+
start_node_id=branch_id,
|
|
1315
|
+
branch_out_id=None,
|
|
1316
|
+
execution_environment=execution_environment,
|
|
1317
|
+
title="Branch execution triggered by demand",
|
|
1318
|
+
)
|
|
1319
|
+
|
|
1204
1320
|
def __init__(self):
|
|
1205
|
-
self.handler_map: Dict[str, "EventHandlerRegistry.HandlerEntry"] = {
|
|
1321
|
+
self.handler_map: Dict[str, "EventHandlerRegistry.HandlerEntry"] = {
|
|
1322
|
+
"stop_blueprint_run": {
|
|
1323
|
+
"callable": self.stop_blueprint_run,
|
|
1324
|
+
"meta": {"name": "stop_blueprint_run", "args": ["payload", "blueprint_runner"]},
|
|
1325
|
+
},
|
|
1326
|
+
"run_blueprint_by_key": {
|
|
1327
|
+
"callable": self.run_blueprint_by_key,
|
|
1328
|
+
"meta": {
|
|
1329
|
+
"name": "run_blueprint_by_key",
|
|
1330
|
+
"args": ["payload", "context", "session", "blueprint_runner", "vault"],
|
|
1331
|
+
},
|
|
1332
|
+
},
|
|
1333
|
+
"run_blueprint_by_id": {
|
|
1334
|
+
"callable": self.run_blueprint_by_id,
|
|
1335
|
+
"meta": {
|
|
1336
|
+
"name": "run_blueprint_by_id",
|
|
1337
|
+
"args": ["payload", "context", "session", "blueprint_runner", "vault"],
|
|
1338
|
+
},
|
|
1339
|
+
},
|
|
1340
|
+
"run_blueprint_via_api": {
|
|
1341
|
+
"callable": self.run_blueprint_via_api,
|
|
1342
|
+
"meta": {
|
|
1343
|
+
"name": "run_blueprint_via_api",
|
|
1344
|
+
"args": ["payload", "context", "session", "blueprint_runner", "vault"],
|
|
1345
|
+
},
|
|
1346
|
+
},
|
|
1347
|
+
"run_blueprint_branch": {
|
|
1348
|
+
"callable": self.run_blueprint_branch,
|
|
1349
|
+
"meta": {
|
|
1350
|
+
"name": "run_blueprint_branch",
|
|
1351
|
+
"args": ["payload", "context", "session", "blueprint_runner", "vault"],
|
|
1352
|
+
},
|
|
1353
|
+
},
|
|
1354
|
+
}
|
|
1206
1355
|
|
|
1207
1356
|
def __iter__(self):
|
|
1208
1357
|
return iter(self.handler_map.keys())
|
|
@@ -1508,6 +1657,12 @@ class EventDeserialiser:
|
|
|
1508
1657
|
payload = _deserialize_bigint_format(payload)
|
|
1509
1658
|
return payload
|
|
1510
1659
|
|
|
1660
|
+
def _transform_tab_change(self, ev: WriterEvent) -> Optional[str]:
|
|
1661
|
+
payload = ev.payload
|
|
1662
|
+
if not isinstance(payload, str):
|
|
1663
|
+
return None
|
|
1664
|
+
return payload
|
|
1665
|
+
|
|
1511
1666
|
|
|
1512
1667
|
class SessionManager:
|
|
1513
1668
|
"""
|
|
@@ -1639,16 +1794,29 @@ class EventHandler:
|
|
|
1639
1794
|
return
|
|
1640
1795
|
self.evaluator.set_state(binding["stateRef"], instance_path, payload)
|
|
1641
1796
|
|
|
1797
|
+
@staticmethod
|
|
1798
|
+
def _get_blueprint_execution_environment(payload, context, session, vault):
|
|
1799
|
+
return {
|
|
1800
|
+
"payload": payload,
|
|
1801
|
+
"context": context,
|
|
1802
|
+
"session": session,
|
|
1803
|
+
"vault": vault,
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1642
1806
|
def _get_blueprint_callable(
|
|
1643
1807
|
self,
|
|
1644
1808
|
blueprint_key: Optional[str] = None,
|
|
1645
1809
|
blueprint_id: Optional[str] = None,
|
|
1646
1810
|
branch_id: Optional[str] = None,
|
|
1647
1811
|
):
|
|
1648
|
-
def fn(payload, context, session):
|
|
1649
|
-
execution_environment =
|
|
1812
|
+
def fn(payload, context, session, vault):
|
|
1813
|
+
execution_environment = self._get_blueprint_execution_environment(
|
|
1814
|
+
payload, context, session, vault
|
|
1815
|
+
)
|
|
1650
1816
|
if blueprint_key:
|
|
1651
|
-
return self.blueprint_runner.run_blueprint_by_key(
|
|
1817
|
+
return self.blueprint_runner.run_blueprint_by_key(
|
|
1818
|
+
blueprint_key, execution_environment
|
|
1819
|
+
)
|
|
1652
1820
|
elif blueprint_id:
|
|
1653
1821
|
return self.blueprint_runner.run_blueprint(
|
|
1654
1822
|
blueprint_id, execution_environment, "Blueprint execution triggered on demand"
|
|
@@ -1664,18 +1832,6 @@ class EventHandler:
|
|
|
1664
1832
|
return fn
|
|
1665
1833
|
|
|
1666
1834
|
def _get_handler_callable(self, handler: str) -> Optional[Callable]:
|
|
1667
|
-
if handler.startswith("$runBlueprint_"):
|
|
1668
|
-
blueprint_key = handler[14:]
|
|
1669
|
-
return self._get_blueprint_callable(blueprint_key=blueprint_key)
|
|
1670
|
-
|
|
1671
|
-
if handler.startswith("$runBlueprintById_"):
|
|
1672
|
-
blueprint_id = handler[18:]
|
|
1673
|
-
return self._get_blueprint_callable(blueprint_id=blueprint_id)
|
|
1674
|
-
|
|
1675
|
-
if handler.startswith("$runBlueprintTriggerBranchById_"):
|
|
1676
|
-
branch_id = handler[31:]
|
|
1677
|
-
return self._get_blueprint_callable(branch_id=branch_id)
|
|
1678
|
-
|
|
1679
1835
|
current_app_process = get_app_process()
|
|
1680
1836
|
handler_registry = current_app_process.handler_registry
|
|
1681
1837
|
callable_handler = handler_registry.find_handler_callable(handler)
|
|
@@ -1690,24 +1846,23 @@ class EventHandler:
|
|
|
1690
1846
|
"context": context_data,
|
|
1691
1847
|
"session": _event_handler_session_info(),
|
|
1692
1848
|
"ui": _event_handler_ui_manager(),
|
|
1849
|
+
"blueprint_runner": self.blueprint_runner,
|
|
1850
|
+
"vault": writer_vault.get_secrets(),
|
|
1693
1851
|
}
|
|
1694
1852
|
|
|
1695
1853
|
def _call_handler_callable(self, handler_callable: Callable, calling_arguments: Dict) -> Any:
|
|
1696
1854
|
current_app_process = get_app_process()
|
|
1697
1855
|
result = None
|
|
1698
|
-
captured_stdout = None
|
|
1699
1856
|
with (
|
|
1700
1857
|
core_ui.use_component_tree(self.session.session_component_tree),
|
|
1701
|
-
|
|
1858
|
+
use_stdout_redirect(
|
|
1859
|
+
lambda entry: self.session_state.add_log_entry("info", "Stdout message", entry)
|
|
1860
|
+
),
|
|
1702
1861
|
):
|
|
1703
1862
|
middlewares_executors = current_app_process.middleware_registry.executors()
|
|
1704
1863
|
result = EventHandlerExecutor.invoke_with_middlewares(
|
|
1705
1864
|
middlewares_executors, handler_callable, calling_arguments
|
|
1706
1865
|
)
|
|
1707
|
-
captured_stdout = f.getvalue()
|
|
1708
|
-
|
|
1709
|
-
if captured_stdout:
|
|
1710
|
-
self.session_state.add_log_entry("info", "Stdout message", captured_stdout)
|
|
1711
1866
|
|
|
1712
1867
|
return result
|
|
1713
1868
|
|
|
@@ -1740,17 +1895,21 @@ class EventHandler:
|
|
|
1740
1895
|
calling_arguments = self._get_calling_arguments(ev, instance_path=None)
|
|
1741
1896
|
return self._call_handler_callable(handler_callable, calling_arguments)
|
|
1742
1897
|
except BaseException as e:
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1898
|
+
if not isinstance(e, BlueprintExecutionError):
|
|
1899
|
+
# Only create a notification and log entry
|
|
1900
|
+
# for non-blueprint errors, as blueprint errors
|
|
1901
|
+
# have their own logging mechanism
|
|
1902
|
+
self.session_state.add_notification(
|
|
1903
|
+
"error",
|
|
1904
|
+
"Runtime Error",
|
|
1905
|
+
f"An error occurred when processing event '{ ev.type }'.",
|
|
1906
|
+
)
|
|
1907
|
+
self.session_state.add_log_entry(
|
|
1908
|
+
"error",
|
|
1909
|
+
"Runtime Exception",
|
|
1910
|
+
f"A runtime exception was raised when processing event '{ ev.type }'.",
|
|
1911
|
+
traceback.format_exc(),
|
|
1912
|
+
)
|
|
1754
1913
|
raise e
|
|
1755
1914
|
|
|
1756
1915
|
def _handle_component_event(self, ev: WriterEvent):
|
|
@@ -1762,7 +1921,13 @@ class EventHandler:
|
|
|
1762
1921
|
target_component = cast(Component, self.session_component_tree.get_component(target_id))
|
|
1763
1922
|
self._handle_binding(ev.type, target_component, instance_path, ev.payload)
|
|
1764
1923
|
calling_arguments = self._get_calling_arguments(ev, instance_path)
|
|
1765
|
-
self.
|
|
1924
|
+
execution_environment = self._get_blueprint_execution_environment(
|
|
1925
|
+
calling_arguments.get("payload"),
|
|
1926
|
+
calling_arguments.get("context"),
|
|
1927
|
+
calling_arguments.get("session"),
|
|
1928
|
+
calling_arguments.get("vault"),
|
|
1929
|
+
)
|
|
1930
|
+
self.blueprint_runner.execute_ui_trigger(target_id, ev.type, execution_environment)
|
|
1766
1931
|
if not target_component.handlers:
|
|
1767
1932
|
return None
|
|
1768
1933
|
handler = target_component.handlers.get(ev.type)
|
writer/core_ui.py
CHANGED
|
@@ -467,6 +467,10 @@ def export_component_tree(component_tree: ComponentTree, mode: ServeMode, only_u
|
|
|
467
467
|
_components.append(_root_component)
|
|
468
468
|
_components += component_tree.get_descendents(root)
|
|
469
469
|
|
|
470
|
+
# filters notes in run mode
|
|
471
|
+
if mode == "run":
|
|
472
|
+
_components = [c for c in _components if c.type != "note"]
|
|
473
|
+
|
|
470
474
|
return {c.id: c.to_dict() for c in _components}
|
|
471
475
|
|
|
472
476
|
class UIError(Exception):
|
writer/evaluator.py
CHANGED
|
@@ -55,34 +55,32 @@ class Evaluator:
|
|
|
55
55
|
raise ValueError(f'Component with id "{component_id}" not found.')
|
|
56
56
|
|
|
57
57
|
field_value = component.content.get(field_key) or default_field_value
|
|
58
|
-
replaced = None
|
|
59
58
|
full_match = self.TEMPLATE_REGEX.fullmatch(field_value)
|
|
60
59
|
|
|
61
|
-
def replacer(matched):
|
|
62
|
-
if matched.
|
|
63
|
-
return matched.
|
|
60
|
+
def replacer(matched: re.Match):
|
|
61
|
+
if matched.group(0)[0] == "\\": # Escaped @, don't evaluate
|
|
62
|
+
return matched.group(0)
|
|
64
63
|
expr = matched.group(1).strip()
|
|
65
64
|
expr_value = self.evaluate_expression(expr, instance_path, base_context)
|
|
66
65
|
if full_match is not None:
|
|
67
66
|
return expr_value
|
|
68
67
|
if as_json:
|
|
69
|
-
|
|
68
|
+
dumped = expr_value
|
|
69
|
+
if not isinstance(dumped, str):
|
|
70
|
+
dumped = json.dumps(dumped)
|
|
71
|
+
else:
|
|
72
|
+
dumped = json.dumps(dumped)[1:-1]
|
|
73
|
+
return re.sub(r'(?<!\\)"', r'\"', dumped)
|
|
70
74
|
if not isinstance(expr_value, str):
|
|
71
75
|
return json.dumps(expr_value)
|
|
72
76
|
return expr_value
|
|
73
77
|
|
|
74
78
|
if full_match is None:
|
|
75
|
-
replaced = field_value
|
|
76
|
-
if as_json:
|
|
77
|
-
# First pass to remove quotes around @{my_var}
|
|
78
|
-
replaced = re.sub(r'"(@{\s*[^"]+?\s*})"', r"\1", field_value)
|
|
79
|
-
replaced = self.TEMPLATE_REGEX.sub(replacer, replaced)
|
|
80
|
-
if as_json:
|
|
81
|
-
replaced = decode_json(replaced)
|
|
79
|
+
replaced = self.TEMPLATE_REGEX.sub(replacer, field_value)
|
|
82
80
|
else:
|
|
83
81
|
replaced = replacer(full_match)
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
if as_json:
|
|
83
|
+
replaced = decode_json(replaced)
|
|
86
84
|
|
|
87
85
|
return replaced
|
|
88
86
|
|
|
@@ -217,16 +215,7 @@ class Evaluator:
|
|
|
217
215
|
state_ref: Any = self.state.user_state
|
|
218
216
|
accessors: List[str] = self.parse_expression(expr, instance_path, base_context)
|
|
219
217
|
|
|
220
|
-
|
|
221
|
-
if isinstance(state_ref, (writer.core.StateProxy, dict)) and accessor in state_ref:
|
|
222
|
-
state_ref = state_ref.get(accessor)
|
|
223
|
-
result = state_ref
|
|
224
|
-
elif isinstance(state_ref, (list)) and state_ref[int(accessor)] is not None:
|
|
225
|
-
state_ref = state_ref[int(accessor)]
|
|
226
|
-
result = state_ref
|
|
227
|
-
elif isinstance(context_ref, dict) and accessor in context_ref:
|
|
228
|
-
context_ref = context_ref.get(accessor)
|
|
229
|
-
result = context_ref
|
|
218
|
+
result = self._apply_accessors(accessors, state_ref, context_ref)
|
|
230
219
|
|
|
231
220
|
if isinstance(result, writer.core.StateProxy):
|
|
232
221
|
return result.to_dict()
|
|
@@ -235,3 +224,28 @@ class Evaluator:
|
|
|
235
224
|
return self.get_env_variable_value(expr)
|
|
236
225
|
|
|
237
226
|
return result
|
|
227
|
+
|
|
228
|
+
def _apply_accessors(self, accessors: List[str], state_ref: Any, context_ref: Any = None) -> Any:
|
|
229
|
+
if not accessors:
|
|
230
|
+
return state_ref
|
|
231
|
+
|
|
232
|
+
result = self._apply_accessor(accessors[0], context_ref)
|
|
233
|
+
if result is None:
|
|
234
|
+
result = self._apply_accessor(accessors[0], state_ref)
|
|
235
|
+
|
|
236
|
+
for accessor in accessors[1:]:
|
|
237
|
+
result = self._apply_accessor(accessor, result)
|
|
238
|
+
|
|
239
|
+
return result
|
|
240
|
+
|
|
241
|
+
def _apply_accessor(self, accessor: str, target: Any) -> Any:
|
|
242
|
+
if isinstance(target, (writer.core.StateProxy, dict)):
|
|
243
|
+
return target.get(accessor)
|
|
244
|
+
|
|
245
|
+
if isinstance(target, list):
|
|
246
|
+
try:
|
|
247
|
+
return target[int(accessor)]
|
|
248
|
+
except IndexError:
|
|
249
|
+
pass
|
|
250
|
+
|
|
251
|
+
return None
|