Skip to content

Commit

Permalink
[minor] Factories instead of meta nodes, and use them for transformer…
Browse files Browse the repository at this point in the history
… nodes (#293)

* Replace evaluated code to-/from-list nodes with actual classes

Leveraging custom constructors

* Develop meta abstraction and make a new home for transforming meta nodes

* Accept node args too

* Introduce a decorator for building the class-IO

* Change paradigm to whether or not the node uses __reduced__ and a constructor

Instead of "Meta" nodes

* Allow direct use of Constructed children

* Move and update constructed stuff

* Add new singleton behaviour so factory-produced classes can pass is-tests

* Apply constructed and class registration updates to the transformers

* Remove (now unused) meta module

* PEP8 newline

* Remove unnecessary __getstate__

The object isn't holding instance level state and older versions of python bork here.

* Add constructed __*state__ compatibility for older versions

* 🐛 add missing `return`

* Format black

* Introduce a new factory pattern

At the cost of requiring factory functions to forgo kwargs, we get object matching for factories and classes, and picklability for instances. Still need to check some edge cases around the use of stuff with a non-trivial qualname.

* Test factories as methods

* Test local scoping

* Add docstrings and hide a function

* Simplify super

* Give demo class in tests have a more generic __init__

* Test and document multiple inheritance

* Stop storing __init__ args

By leveraging `__new__` and `__getnewargs_ex__`

* Add clearing methods

In case you want to change some constructor behaviour and clear the access cache. Not sure what should be cached at the end of the day, but for now just give users a shortcut for clearing it.

* Use snippets.factory.classfactory and typing.ClassVar for transformers

* Revert singleton

* Format black

* Remove constructed

It's superceded by the snippets.factory stuff

* Gently rename things for when the factory comes from a decorator

* Allow factory made classes to also come from decorators

* Format black

---------

Co-authored-by: pyiron-runner <[email protected]>
  • Loading branch information
liamhuber and pyiron-runner authored Apr 29, 2024
1 parent 744ebfc commit 37fd191
Show file tree
Hide file tree
Showing 9 changed files with 1,109 additions and 62 deletions.
12 changes: 4 additions & 8 deletions pyiron_workflow/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,15 @@ def Workflow(self):
@property
def meta(self):
if self._meta is None:
from pyiron_workflow.meta import (
input_to_list,
list_to_output,
)
from pyiron_workflow.loops import while_loop
from pyiron_workflow.loops import for_loop
from pyiron_workflow.transform import inputs_to_list, list_to_outputs
from pyiron_workflow.loops import for_loop, while_loop
from pyiron_workflow.snippets.dotdict import DotDict

self._meta = DotDict(
{
for_loop.__name__: for_loop,
input_to_list.__name__: input_to_list,
list_to_output.__name__: list_to_output,
inputs_to_list.__name__: inputs_to_list,
list_to_outputs.__name__: list_to_outputs,
while_loop.__name__: while_loop,
}
)
Expand Down
23 changes: 19 additions & 4 deletions pyiron_workflow/io_preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import inspect
import warnings
from abc import ABC, abstractmethod
from functools import lru_cache
from functools import lru_cache, wraps
from textwrap import dedent
from types import FunctionType
from typing import Any, get_args, get_type_hints, Literal, Optional, TYPE_CHECKING
Expand Down Expand Up @@ -79,6 +79,22 @@ def preview_io(cls) -> DotDict[str:dict]:
)


def builds_class_io(subclass_factory: callable[..., type[HasIOPreview]]):
"""
A decorator for factories producing subclasses of `HasIOPreview` to invoke
:meth:`preview_io` after the class is created, thus ensuring the IO has been
constructed at the class level.
"""

@wraps(subclass_factory)
def wrapped(*args, **kwargs):
node_class = subclass_factory(*args, **kwargs)
node_class.preview_io()
return node_class

return wrapped


class ScrapesIO(HasIOPreview, ABC):
"""
A mixin class for scraping IO channel information from a specific class method's
Expand Down Expand Up @@ -391,14 +407,15 @@ def as_decorated_node_decorator(
):
output_labels = None if len(output_labels) == 0 else output_labels

@builds_class_io
def as_decorated_node(io_defining_function: callable):
if not callable(io_defining_function):
raise AttributeError(
f"Tried to create a new child class of {parent_class.__name__}, "
f"but got {io_defining_function} instead of a callable."
)

decorated_node_class = type(
return type(
io_defining_function.__name__,
(parent_class,), # Define parentage
{
Expand All @@ -409,8 +426,6 @@ def as_decorated_node(io_defining_function: callable):
**parent_class_attr_overrides,
},
)
decorated_node_class.preview_io() # Construct everything
return decorated_node_class

return as_decorated_node

Expand Down
6 changes: 3 additions & 3 deletions pyiron_workflow/loops.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pyiron_workflow import Workflow
from pyiron_workflow.function import Function
from pyiron_workflow.macro import Macro
from pyiron_workflow.meta import input_to_list, list_to_output
from pyiron_workflow.transform import inputs_to_list, list_to_outputs
from pyiron_workflow.node import Node


Expand Down Expand Up @@ -92,7 +92,7 @@ def for_loop(
f"{l}={l.upper()}[n]" if l in iterate_on else f"{l}={l}"
for l in input_preview.keys()
).rstrip(" ")
input_label = 'f"inp{n}"'
input_label = 'f"item_{n}"'
returns = ", ".join(
f'self.children["{label.upper()}"]' for label in output_preview.keys()
)
Expand All @@ -106,7 +106,7 @@ def {node_name}(self, {macro_args}):
from {loop_body_class.__module__} import {loop_body_class.__name__}
for label in [{output_labels}]:
input_to_list({length})(label=label, parent=self)
inputs_to_list({length}, label=label, parent=self)
for n in range({length}):
body_node = {loop_body_class.__name__}(
Expand Down
46 changes: 0 additions & 46 deletions pyiron_workflow/meta.py

This file was deleted.

Loading

0 comments on commit 37fd191

Please sign in to comment.