importdataclassesimportjsonimporttypingastimportznflowimportznflow.handlerimportznjsonfromzntrackimportconverterfromzntrack.configimportZNTRACK_FILE_PATH,FieldTypesfromzntrack.fields.baseimportfieldfromzntrack.nodeimportNodefromzntrack.utils.filesystemimportresolve_state_file_path_T=t.TypeVar("_T")def_deps_getter(self:"Node",name:str):zntrack_path=resolve_state_file_path(self.state.fs,self.state.path,ZNTRACK_FILE_PATH)withself.state.fs.open(zntrack_path)asf:content=json.load(f)[self.name][name]# TODO: Ensure deps are loaded from the correct revisiontry:content=znjson.loads(json.dumps(content),cls=znjson.ZnDecoder.from_converters([converter.create_node_converter(remote=self.state.remote,rev=self.state.rev,path=self.state.path,),converter.ConnectionConverter,converter.CombinedConnectionsConverter,converter.DVCImportPathConverter,converter.DataclassConverter,],add_default=True,),)exceptModuleNotFoundError:# If external dataclass module can't be imported, return NOT_AVAILABLE# The enhanced NOT_AVAILABLE object will provide helpful errors when accessedfromzntrack.configimportNOT_AVAILABLEreturnNOT_AVAILABLEexceptAttributeErrorase:# Only catch AttributeErrors related to missing module attributesif"module"instr(e).lower()or"attribute"instr(e).lower():fromzntrack.configimportNOT_AVAILABLEreturnNOT_AVAILABLE# Re-raise other AttributeErrors as they might indicate different issuesraiseifisinstance(content,converter.DataclassContainer):content=content.get_with_params(self.name,name,index=None,fs=self.state.fs,path=self.state.path,# type: ignore)ifisinstance(content,list):new_content=[]idx=0forvalincontent:ifisinstance(val,converter.DataclassContainer):new_content.append(val.get_with_params(self.name,name,idx,fs=self.state.fs,path=self.state.path,# type: ignore))idx+=1# index only runs over dataclasseselse:new_content.append(val)content=new_contentcontent=znflow.handler.UpdateConnectors()(content)returncontent@t.overloaddefdeps()->t.Any:...@t.overloaddefdeps(default:_T,**kwargs)->_T:...
[docs]defdeps(default=dataclasses.MISSING,**kwargs)->t.Any:"""Define dependencies for a node. A Node dependency field can be used to pass data from one node to another. It can not be used to pass anything that is not a ``zntrack.Node`` or a ``dataclass``. Parameters ---------- default : Any, optional Should not be set on the class level. Examples -------- >>> import zntrack >>> class MyFirstNode(zntrack.Node): ... outs: int = zntrack.outs() ... ... def run(self) -> None: ... self.outs = 42 ... >>> class MySecondNode(zntrack.Node): ... deps: int = zntrack.deps() ... ... def run(self) -> None: ... ... >>> with zntrack.Project() as project: ... node1 = MyFirstNode() ... node2 = MySecondNode(deps=node1.outs) >>> project.build() """returnfield(default=default,load_fn=_deps_getter,field_type=FieldTypes.DEPS,**kwargs,)