Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Docstrings to base.py #35

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
562 changes: 562 additions & 0 deletions examples/example_01.ipynb

Large diffs are not rendered by default.

224 changes: 224 additions & 0 deletions examples/example_02.ipynb

Large diffs are not rendered by default.

212 changes: 212 additions & 0 deletions examples/example_03.ipynb

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ multi_line_output = 3

[tool.ruff]
line-length = 90
select = ["E", "F"] #, "D"] #, "N", "C", "ANN"]
select = ["E", "F", "D"]#, "N", "C", "ANN"]
exclude = [
"tests",
]
extend-ignore = [
"D213", "D203"
]
562 changes: 0 additions & 562 deletions tmp/example_01.ipynb

This file was deleted.

224 changes: 0 additions & 224 deletions tmp/example_02.ipynb

This file was deleted.

211 changes: 0 additions & 211 deletions tmp/example_03.ipynb

This file was deleted.

121 changes: 113 additions & 8 deletions znflow/base.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""The base module of znflow."""
from __future__ import annotations

import contextlib
Expand Down Expand Up @@ -29,6 +30,12 @@ class Property:
"""

def __init__(self, fget=None, fset=None, fdel=None, doc=None):
"""Init method of the property class.

References
----------
Adapted from https://docs.python.org/3/howto/descriptor.html#properties
"""
self.fget = disable_graph()(fget)
self.fset = disable_graph()(fset)
self.fdel = disable_graph()(fdel)
Expand All @@ -38,36 +45,78 @@ def __init__(self, fget=None, fset=None, fdel=None, doc=None):
self._name = ""

def __set_name__(self, owner, name):
"""Set Name Method of the Property class.

References
----------
Adapted from https://docs.python.org/3/howto/descriptor.html#properties
"""
self._name = name

def __get__(self, obj, objtype=None):
"""Get Method of the Property class.

References
----------
Adapted from https://docs.python.org/3/howto/descriptor.html#properties
"""
if obj is None:
return self
if self.fget is None:
raise AttributeError(f"property '{self._name}' has no getter")
return self.fget(obj)

def __set__(self, obj, value):
"""Set Method of the Property class.

References
----------
Adapted from https://docs.python.org/3/howto/descriptor.html#properties
"""
if self.fset is None:
raise AttributeError(f"property '{self._name}' has no setter")
self.fset(obj, value)

def __delete__(self, obj):
"""Delete Method of the Property class.

References
----------
Adapted from https://docs.python.org/3/howto/descriptor.html#properties
"""
if self.fdel is None:
raise AttributeError(f"property '{self._name}' has no deleter")
self.fdel(obj)

def getter(self, fget):
"""Getter Method of the Property class.

References
----------
Adapted from https://docs.python.org/3/howto/descriptor.html#properties
"""
prop = type(self)(fget, self.fset, self.fdel, self.__doc__)
prop._name = self._name
return prop

def setter(self, fset):
"""Setter Method of the Property class.

References
----------
Adapted from https://docs.python.org/3/howto/descriptor.html#properties
"""
prop = type(self)(self.fget, fset, self.fdel, self.__doc__)
prop._name = self._name
return prop

def deleter(self, fdel):
"""Set delete method for Property class.

References
----------
Adapted from https://docs.python.org/3/howto/descriptor.html#properties
"""
prop = type(self)(self.fget, self.fset, fdel, self.__doc__)
prop._name = self._name
return prop
Expand Down Expand Up @@ -98,23 +147,36 @@ class NodeBaseMixin:

@property
def uuid(self):
"""A method that generates a UUID to create a hashable object for each node."""
return self._uuid

@uuid.setter
def uuid(self, value):
"""Check for an existing UUID.

If no UUID exists, it sets the previously defined UUID for the node.

Raises
------
ValueError
If a UUID is already set for the current node.
"""
if self._uuid is not None:
raise ValueError("uuid is already set")
self._uuid = value

def run(self):
"""Run Method of NodeBaseMixin."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The run method is a really important abstract method. It's the method that is executed upon the graph run call.

raise NotImplementedError


def get_graph():
"""Get Graph from the NodeBaseMixin class."""
return NodeBaseMixin._graph_


def set_graph(value):
"""Set a value for the NodeBaseMixin graph."""
NodeBaseMixin._graph_ = value


Expand All @@ -132,44 +194,62 @@ def get_attribute(obj, name, default=_get_attribute_none):
@dataclasses.dataclass(frozen=True)
class Connection:
"""A Connector for Nodes.
instance: either a Node or FunctionFuture
attribute:
Node.attribute

Instance
--------
Either a Node or FunctionFuture.

Attributes
----------
attribute : Node.attribute
or FunctionFuture.result
or None if the class is passed and not an attribute
or None if the class is passed and not an attribute.
"""

instance: any
attribute: any
item: any = None

def __post_init__(self):
"""Raise a Valueerror if a private attribute is called."""
if self.attribute is not None and self.attribute.startswith("_"):
raise ValueError("Private attributes are not allowed.")

def __getitem__(self, item):
"""Create a new object of the same type as self with values from changes."""
return dataclasses.replace(self, instance=self, attribute=None, item=item)

def __iter__(self):
"""Raise TypeError when iterating over itself."""
raise TypeError(f"Can not iterate over {self}.")

def __add__(
self, other: typing.Union[Connection, FunctionFuture, CombinedConnections]
) -> CombinedConnections:
"""Add Method of the Connection class.

Adds instances onto eachother.

Raises
------
TypeError when two types cannot be added.
"""
if isinstance(other, (Connection, FunctionFuture, CombinedConnections)):
return CombinedConnections(connections=[self, other])
raise TypeError(f"Can not add {type(other)} to {type(self)}.")

def __radd__(self, other):
"""Enable 'sum([a, b], [])'"""
"""Enable 'sum([a, b], [])'."""
return self if other == [] else self.__add__(other)

@property
def uuid(self):
"""Gets value of the UUID."""
return self.instance.uuid

@property
def result(self):
"""Returns the instance and if available, also the attribute."""
if self.attribute:
result = getattr(self.instance, self.attribute)
elif isinstance(self.instance, (FunctionFuture, self.__class__)):
Expand All @@ -190,7 +270,6 @@ class CombinedConnections:

Examples
--------

>>> import znflow
>>> @znflow.nodfiy
>>> def add(size) -> list:
Expand Down Expand Up @@ -235,17 +314,20 @@ def __add__(
raise TypeError(f"Can not add {type(other)} to {type(self)}.")

def __radd__(self, other):
"""Enable 'sum([a, b], [])'"""
"""Enable 'sum([a, b], [])'."""
return self if other == [] else self.__add__(other)

def __getitem__(self, item):
"""Create a new object of the same type as self with values from changes."""
return dataclasses.replace(self, item=item)

def __iter__(self):
"""Raise TypeError when iterating over itself."""
raise TypeError(f"Can not iterate over {self}.")

@property
def result(self):
"""TODO."""
try:
results = []
for connection in self.connections:
Expand All @@ -260,6 +342,15 @@ def result(self):

@dataclasses.dataclass
class FunctionFuture(NodeBaseMixin):
"""A class that creates a future object out of a function.

Attributes
----------
function : callable
args : tuple
kwargs : dict
"""

function: typing.Callable
args: typing.Tuple
kwargs: typing.Dict
Expand All @@ -270,21 +361,35 @@ class FunctionFuture(NodeBaseMixin):
_protected_ = NodeBaseMixin._protected_ + ["function", "args", "kwargs"]

def run(self):
"""Run Method of the FunctionFuture class.

Executes the function with the given arguments and saves the result.
"""
self.result = self.function(*self.args, **self.kwargs)

def __getitem__(self, item):
"""Get the object with all the information of the Connection class."""
return Connection(instance=self, attribute=None, item=item)

def __iter__(self):
"""Raise TypeError when iterating over itself."""
raise TypeError(f"Can not iterate over {self}.")

def __add__(
self, other: typing.Union[Connection, FunctionFuture, CombinedConnections]
) -> CombinedConnections:
"""Add Method of the FunctionFuture class.

Adds instances onto eachother.

Raises
------
TypeError when two types cannot be added.
"""
if isinstance(other, (Connection, FunctionFuture, CombinedConnections)):
return CombinedConnections(connections=[self, other])
raise TypeError(f"Can not add {type(other)} to {type(self)}.")

def __radd__(self, other):
"""Enable 'sum([a, b], [])'"""
"""Enable 'sum([a, b], [])'."""
return self if other == [] else self.__add__(other)
1 change: 1 addition & 0 deletions znflow/graph.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""The graph module of ZnFlow."""
import functools
import logging
import typing
Expand Down
1 change: 1 addition & 0 deletions znflow/node.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""The node module of ZnFlow."""
from __future__ import annotations

import functools
Expand Down
1 change: 0 additions & 1 deletion znflow/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ def handle(self, value, **kwargs):
@functools.singledispatchmethod
def _handle(self, value, **kwargs):
"""Fallback handling if no siggledispatch was triggered."""

result = self.default(value, **kwargs)
if result is not value:
self.updated = True
Expand Down