hpcflow / hpcflow-new

Mozilla Public License 2.0
0 stars 5 forks source link

Can't read schema_parameters or actions of Element #689

Open dkfellows opened 2 months ago

dkfellows commented 2 months ago

While doing type analysis, I've discovered that the schema_parameters and actions properties of hpcflow.sdk.core.element.Element appear to not be possible to retrieve; they reference properties of a hpcflow.sdk.core.actions.ElementAction that appear to not exist (at least in commit 2abdc99268d20c7c317c055af137f0f2852ce80d).

Assuming the type analysis is correct. That's ongoing... but looks correct at this point.

aplowman commented 2 months ago

I think the Element.actions type annotation is wrong. I can read the properties without issue:

import hpcflow.app as hf

wk = hf.make_demo_workflow("workflow_1")

print(wk.tasks[0].elements[0].schema_parameters) 
# ==> ['resources.any', 'outputs.p2', 'inputs.p1']

print(wk.tasks[0].elements[0].actions)
# ==> {1: ElementAction(iter_ID=0, scope='main', action_idx=1, num_runs=1)}

I suppose: https://github.com/hpcflow/hpcflow-new/blob/50fd0010fecd2bdd2fc2abe2aaceddeec39015b7/hpcflow/sdk/core/element.py#L1081 should read:

def actions(self) -> Dict[int, app.ElementAction]: 
dkfellows commented 2 months ago

I had wondered about that. The problem was I (or rather my IDE) couldn't find what was implementing the properties.

aplowman commented 2 months ago

I'm not surprised IDEs are having problems finding things, it is quite dynamic. I'll be interested to see how you get on with your type analysis.

For example, in the case above: app.ElementAction calls this module-level __getattr__*, which in turn calls __getattr__ on the BaseApp instance (for hpcflow) or the App instance (for "derived apps", like MatFlow). This, in turn, calls this method: https://github.com/hpcflow/hpcflow-new/blob/50fd0010fecd2bdd2fc2abe2aaceddeec39015b7/hpcflow/sdk/app.py#L257, which returns the actual class!

The reason for this complexity is so "derived apps" (like MatFlow) can be used without any reference to hpcflow. So for example, we can import a WorkflowTemplate class in MatFlow, like: from matflow import WorkflowTemplate. This class is then specific to MatFlow (it is in fact a subclass of the corresponding class defined in the hpcflow.sdk), and it can have a docstring that references the app as MatFlow, rather than hpcflow:

https://github.com/hpcflow/hpcflow-new/blob/50fd0010fecd2bdd2fc2abe2aaceddeec39015b7/hpcflow/sdk/core/workflow.py#L88

Hope that helps a bit!


* https://peps.python.org/pep-0562/

dkfellows commented 1 month ago

With the type analysis, the main trick is the use of typing.TYPE_CHECKING (as well as from __future__ import annotations, which I see you already know) to let me directly import all the classes without worrying about import circularity.

I'm also using TypedDict, Protocol and Generic/TypeVar where it seems appropriate. So far, it's not been anything like as nasty as the complex mess that was inside one of my previous projects (which did things with database-backed sparse matrices that were amazing/horrible).