funcnodes-core 0.2.2__tar.gz → 0.2.4__tar.gz

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.
Files changed (33) hide show
  1. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/PKG-INFO +1 -1
  2. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/__init__.py +1 -1
  3. funcnodes_core-0.2.4/funcnodes_core/_logging.py +215 -0
  4. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/lib/lib.py +4 -4
  5. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/node.py +7 -0
  6. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/nodemaker.py +0 -7
  7. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/pyproject.toml +1 -1
  8. funcnodes_core-0.2.2/funcnodes_core/_logging.py +0 -100
  9. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/LICENSE +0 -0
  10. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/README.md +0 -0
  11. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/_setup.py +0 -0
  12. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/config.py +0 -0
  13. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/data.py +0 -0
  14. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/decorator/__init__.py +0 -0
  15. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/eventmanager.py +0 -0
  16. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/exceptions.py +0 -0
  17. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/graph.py +0 -0
  18. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/io.py +0 -0
  19. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/lib/__init__.py +0 -0
  20. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/lib/libfinder.py +0 -0
  21. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/lib/libparser.py +0 -0
  22. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/nodespace.py +0 -0
  23. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/triggerstack.py +0 -0
  24. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/utils/__init__.py +0 -0
  25. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/utils/data.py +0 -0
  26. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/utils/functions.py +0 -0
  27. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/utils/nodeutils.py +0 -0
  28. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/utils/plugins.py +0 -0
  29. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/utils/plugins_types.py +0 -0
  30. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/utils/saving.py +0 -0
  31. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/utils/serialization.py +0 -0
  32. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/utils/special_types.py +0 -0
  33. {funcnodes_core-0.2.2 → funcnodes_core-0.2.4}/funcnodes_core/utils/wrapper.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: funcnodes-core
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: core package for funcnodes
5
5
  License: MIT
6
6
  Author: Julian Kimmig
@@ -1,4 +1,4 @@
1
- __version__ = "0.2.2"
1
+ __version__ = "0.2.4"
2
2
 
3
3
  from .io import (
4
4
  NodeInput,
@@ -0,0 +1,215 @@
1
+ import logging
2
+ from logging.handlers import RotatingFileHandler
3
+ from .config import CONFIG_DIR
4
+ import os
5
+
6
+ LOGGINGDIR = os.path.join(CONFIG_DIR, "logs")
7
+ if not os.path.exists(LOGGINGDIR):
8
+ os.makedirs(LOGGINGDIR)
9
+
10
+
11
+ _formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
12
+
13
+ # Add the handler to the logger
14
+
15
+
16
+ def _overwrite_add_handler(logger):
17
+ """
18
+ Overwrites the addHandler method of the given logger to ensure handlers are added with a formatter
19
+ and prevent duplicate handlers from being added.
20
+
21
+ Args:
22
+ logger (logging.Logger): The logger whose addHandler method will be overwritten.
23
+
24
+ Returns:
25
+ None
26
+
27
+ Example:
28
+ >>> _overwrite_add_handler(FUNCNODES_LOGGER)
29
+ """
30
+ _old_add_handler = logger.addHandler
31
+
32
+ def _new_add_handler(hdlr):
33
+ """
34
+ Adds a handler to the given logger if it's not already added,
35
+ and sets the formatter for the handler.
36
+
37
+ Args:
38
+ hdlr (logging.Handler): The handler to add to the logger.
39
+
40
+ Returns:
41
+ None
42
+ """
43
+ hdlr.setFormatter(_formatter)
44
+ if hdlr not in logger.handlers:
45
+ _old_add_handler(hdlr)
46
+
47
+ logger.addHandler = _new_add_handler
48
+
49
+
50
+ def getChildren(logger: logging.Logger):
51
+ """
52
+ Retrieves all child loggers of a given logger.
53
+
54
+ Args:
55
+ logger (logging.Logger): The logger for which to retrieve the child loggers.
56
+
57
+ Returns:
58
+ set: A set of child loggers of the given logger.
59
+
60
+ Example:
61
+ >>> getChildren(FUNCNODES_LOGGER)
62
+ """
63
+
64
+ def _hierlevel(_logger: logging.Logger):
65
+ """
66
+ Helper function to determine the hierarchy level of a logger.
67
+
68
+ Args:
69
+ _logger (logging.Logger): The logger whose hierarchy level is to be determined.
70
+
71
+ Returns:
72
+ int: The hierarchy level of the logger.
73
+ """
74
+ if _logger is _logger.manager.root:
75
+ return 0
76
+ return 1 + _logger.name.count(".")
77
+
78
+ d = dict(logger.manager.loggerDict)
79
+ children = set()
80
+ for item in list(d.values()):
81
+ try:
82
+ # catch Exception because ne cannot aquire the logger _lock
83
+ if (
84
+ isinstance(item, logging.Logger)
85
+ and item.parent is logger
86
+ and _hierlevel(item) == 1 + _hierlevel(item.parent)
87
+ ):
88
+ children.add(item)
89
+ except Exception:
90
+ pass
91
+
92
+ return children
93
+
94
+
95
+ def _update_logger_handlers(logger: logging.Logger):
96
+ """
97
+ Updates the handlers for the given logger, ensuring it has a StreamHandler and a RotatingFileHandler.
98
+ The log files are stored in the logs directory, and the log formatting is set correctly.
99
+ Also updates the handlers for all child loggers.
100
+
101
+ Args:
102
+ logger (logging.Logger): The logger to update handlers for.
103
+
104
+ Returns:
105
+ None
106
+
107
+ Example:
108
+ >>> _update_logger_handlers(FUNCNODES_LOGGER)
109
+ """
110
+
111
+ has_stream_handler = False
112
+ for hdlr in list(logger.handlers):
113
+ if isinstance(hdlr, logging.StreamHandler):
114
+ has_stream_handler = True
115
+ hdlr.setFormatter(_formatter)
116
+
117
+ if isinstance(hdlr, RotatingFileHandler):
118
+ if hdlr.baseFilename == os.path.join(LOGGINGDIR, f"{logger.name}.log"):
119
+ hdlr.close()
120
+ logger.removeHandler(hdlr)
121
+ continue
122
+
123
+ if isinstance(hdlr, logging.Handler):
124
+ hdlr.setFormatter(_formatter)
125
+
126
+ if not has_stream_handler:
127
+ ch = logging.StreamHandler()
128
+ ch.setFormatter(_formatter)
129
+ logger.addHandler(ch)
130
+
131
+ fh = RotatingFileHandler(
132
+ os.path.join(LOGGINGDIR, f"{logger.name}.log"),
133
+ maxBytes=1024 * 1024 * 5,
134
+ backupCount=5,
135
+ )
136
+ fh.setFormatter(_formatter)
137
+ logger.addHandler(fh)
138
+
139
+ # get child loggers
140
+ for child in getChildren(logger):
141
+ _update_logger_handlers(child)
142
+
143
+
144
+ def get_logger(name, propagate=True):
145
+ """
146
+ Returns a logger with the given name as a child of FUNCNODES_LOGGER,
147
+ and ensures the logger is set up with appropriate handlers.
148
+
149
+ Args:
150
+ name (str): The name of the logger to retrieve.
151
+ propagate (bool): Whether to propagate the logger's messages to its parent logger.
152
+
153
+ Returns:
154
+ logging.Logger: The logger with the given name, configured with appropriate handlers.
155
+
156
+ Example:
157
+ >>> get_logger("foo")
158
+ """
159
+ sublogger = FUNCNODES_LOGGER.getChild(name)
160
+ _overwrite_add_handler(sublogger)
161
+ sublogger.propagate = propagate
162
+ _update_logger_handlers(sublogger)
163
+
164
+ return sublogger
165
+
166
+
167
+ def set_logging_dir(path):
168
+ """
169
+ Sets a custom directory path for storing log files. If the directory does not exist, it will be created.
170
+ After updating the directory, the logger's handlers will be updated accordingly.
171
+
172
+ Args:
173
+ path (str): The directory path where log files should be stored.
174
+
175
+ Returns:
176
+ None
177
+
178
+ Example:
179
+ >>> set_logging_dir("/path/to/custom/logs")
180
+ """
181
+ global LOGGINGDIR
182
+ LOGGINGDIR = path
183
+ if not os.path.exists(path):
184
+ os.makedirs(path)
185
+ _update_logger_handlers(FUNCNODES_LOGGER)
186
+
187
+
188
+ def set_format(fmt: str):
189
+ """
190
+ Sets the log formatting string. The format string will be used for all log handlers.
191
+
192
+ Args:
193
+ fmt (str): The format string for log messages.
194
+
195
+ Returns:
196
+ None
197
+
198
+ Example:
199
+ >>> set_format("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
200
+ """
201
+
202
+ global _formatter
203
+ _formatter = logging.Formatter(fmt)
204
+ _update_logger_handlers(FUNCNODES_LOGGER)
205
+
206
+
207
+ FUNCNODES_LOGGER = logging.getLogger("funcnodes")
208
+
209
+ FUNCNODES_LOGGER.setLevel(logging.INFO)
210
+ _overwrite_add_handler(FUNCNODES_LOGGER)
211
+ _update_logger_handlers(FUNCNODES_LOGGER)
212
+ set_logging_dir(LOGGINGDIR)
213
+
214
+
215
+ __all__ = ["FUNCNODES_LOGGER", "get_logger", "set_logging_dir", "set_format"]
@@ -1,5 +1,5 @@
1
1
  from __future__ import annotations
2
- from typing import List, Optional, TypedDict, Dict, Type, Tuple, Set
2
+ from typing import List, Optional, TypedDict, Dict, Type, Tuple, Set, Sequence
3
3
  from funcnodes_core.node import Node, SerializedNodeClass
4
4
  from funcnodes_core.utils.serialization import JSONEncoder, Encdata
5
5
  from dataclasses import dataclass, field
@@ -180,7 +180,7 @@ def get_node_in_shelf(shelf: Shelf, nodeid: str) -> Tuple[int, Type[Node]]:
180
180
  raise NodeClassNotFoundError(f"Node with id {nodeid} not found")
181
181
 
182
182
 
183
- def update_nodes_in_shelf(shelf: Shelf, nodes: List[Type[Node]]):
183
+ def update_nodes_in_shelf(shelf: Shelf, nodes: Sequence[Type[Node]]):
184
184
  """
185
185
  Adds nodes to a shelf
186
186
  """
@@ -347,7 +347,7 @@ class Library(EventEmitterMixin):
347
347
  @emit_after()
348
348
  def add_nodes(
349
349
  self,
350
- nodes: List[Type[Node]],
350
+ nodes: Sequence[Type[Node]],
351
351
  shelf: str | List[str],
352
352
  ):
353
353
  if isinstance(shelf, str):
@@ -403,7 +403,7 @@ class Library(EventEmitterMixin):
403
403
  i, _ = get_node_in_shelf(shelf, node.node_id)
404
404
  shelf.nodes.pop(i)
405
405
 
406
- def remove_nodeclasses(self, nodes: List[Type[Node]]):
406
+ def remove_nodeclasses(self, nodes: Sequence[Type[Node]]):
407
407
  for node in nodes:
408
408
  self.remove_nodeclass(node)
409
409
 
@@ -345,6 +345,7 @@ class Node(EventEmitterMixin, ABC, metaclass=NodeMeta):
345
345
  self._inputs: List[NodeInput] = []
346
346
  self._outputs: List[NodeOutput] = []
347
347
  self._triggerstack: Optional[TriggerStack] = None
348
+ self._trigger_open = False
348
349
  self._requests_trigger = False
349
350
  self.asynceventmanager = AsyncEventManager(self)
350
351
  if uuid is None and id is not None:
@@ -797,6 +798,8 @@ class Node(EventEmitterMixin, ABC, metaclass=NodeMeta):
797
798
  """Wraps the node's function to handle the triggering of events before and after its execution."""
798
799
  # set the trigger event
799
800
  await self.asynceventmanager.set_and_clear("triggered")
801
+ await asyncio.sleep(self._pretrigger_delay)
802
+ self._trigger_open = False
800
803
  self.emit("triggerstart")
801
804
  # run the function
802
805
 
@@ -852,6 +855,8 @@ class Node(EventEmitterMixin, ABC, metaclass=NodeMeta):
852
855
  # if the node is ready to trigger, trigger it
853
856
  if self.ready_to_trigger():
854
857
  self.trigger()
858
+ elif self._trigger_open:
859
+ return
855
860
  else:
856
861
  # otherwise set the _requests_trigger attribute to True
857
862
  self._requests_trigger = True
@@ -914,6 +919,8 @@ class Node(EventEmitterMixin, ABC, metaclass=NodeMeta):
914
919
  raise InTriggerError("Node is already in trigger")
915
920
  if triggerstack is None:
916
921
  triggerstack = TriggerStack()
922
+ self._pretrigger_delay = 0.02 # 20ms
923
+ self._trigger_open = True
917
924
  triggerlogger.debug(f"triggering {self}")
918
925
  self._triggerstack = triggerstack
919
926
  self._triggerstack.append(self())
@@ -91,13 +91,6 @@ def node_class_maker(
91
91
  """
92
92
  A wrapper for the exposed function that sets the output values of the node.
93
93
  """
94
- print(
95
- "BBBtriggering",
96
- self,
97
- {ip.name: ip.value for ip in self.inputs.values()},
98
- args,
99
- kwargs,
100
- )
101
94
  outs = await asyncfunc(*args, **kwargs)
102
95
  if len(outputs) > 1:
103
96
  for op, out in zip(outputs, outs):
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "funcnodes-core"
3
- version = "0.2.2"
3
+ version = "0.2.4"
4
4
  description = "core package for funcnodes"
5
5
  authors = ["Julian Kimmig <julian.kimmig@linkdlab.de>"]
6
6
  readme = "README.md"
@@ -1,100 +0,0 @@
1
- import logging
2
- from logging.handlers import RotatingFileHandler
3
- from .config import CONFIG_DIR
4
- import os
5
-
6
- LOGGINGDIR = os.path.join(CONFIG_DIR, "logs")
7
- if not os.path.exists(LOGGINGDIR):
8
- os.makedirs(LOGGINGDIR)
9
-
10
- FUNCNODES_LOGGER = logging.getLogger("funcnodes")
11
-
12
- FUNCNODES_LOGGER.setLevel(logging.INFO)
13
-
14
-
15
- ch = logging.StreamHandler()
16
-
17
- formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
18
-
19
- # Add the handler to the logger
20
-
21
-
22
- def _overwrite_add_handler(logger):
23
- """
24
- Overwrites the addHandler method of the given logger.
25
-
26
- Args:
27
- logger (Logger): The logger to overwrite the addHandler method for.
28
-
29
- Returns:
30
- None.
31
-
32
- Examples:
33
- >>> _overwrite_add_handler(FUNCNODES_LOGGER)
34
- """
35
- _old_add_handler = logger.addHandler
36
-
37
- def _new_add_handler(hdlr):
38
- """
39
- Adds a handler to the given logger.
40
-
41
- Args:
42
- hdlr (Handler): The handler to add to the logger.
43
-
44
- Returns:
45
- None.
46
-
47
- Examples:
48
- >>> _new_add_handler(ch)
49
- """
50
- hdlr.setFormatter(formatter)
51
- if hdlr not in logger.handlers:
52
- _old_add_handler(hdlr)
53
-
54
- logger.addHandler = _new_add_handler
55
-
56
-
57
- _overwrite_add_handler(FUNCNODES_LOGGER)
58
-
59
- FUNCNODES_LOGGER.addHandler(ch)
60
-
61
-
62
- def set_logging_dir(path):
63
- if not os.path.exists(path):
64
- os.makedirs(path)
65
- for hdlr in FUNCNODES_LOGGER.handlers:
66
- if isinstance(hdlr, RotatingFileHandler):
67
- if hdlr.baseFilename.endswith("funcnodes.log"):
68
- hdlr.close()
69
- FUNCNODES_LOGGER.removeHandler(hdlr)
70
-
71
- fh = RotatingFileHandler(
72
- os.path.join(path, "funcnodes.log"), maxBytes=1024 * 1024 * 5, backupCount=5
73
- )
74
- fh.setFormatter(formatter)
75
- FUNCNODES_LOGGER.addHandler(fh)
76
-
77
-
78
- set_logging_dir(LOGGINGDIR)
79
-
80
-
81
- def get_logger(name, propagate=True):
82
- """
83
- Returns a logger with the given name.
84
-
85
- Args:
86
- name (str): The name of the logger.
87
- propagate (bool): Whether to propagate the logger's messages to its parent logger.
88
-
89
- Returns:
90
- Logger: The logger with the given name.
91
-
92
- Examples:
93
- >>> get_logger("funcnodes")
94
- """
95
- sublogger = FUNCNODES_LOGGER.getChild(name)
96
- _overwrite_add_handler(sublogger)
97
- sublogger.propagate = propagate
98
- sublogger.addHandler(ch)
99
- # _init_logger(sublogger)
100
- return sublogger
File without changes
File without changes