interactive-pipe 0.8.4__tar.gz → 0.8.6__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 (62) hide show
  1. {interactive_pipe-0.8.4/src/interactive_pipe.egg-info → interactive_pipe-0.8.6}/PKG-INFO +7 -2
  2. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/pyproject.toml +1 -1
  3. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/readme.md +6 -1
  4. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/__init__.py +1 -1
  5. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/core/cache.py +7 -5
  6. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/core/engine.py +15 -11
  7. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/core/filter.py +43 -24
  8. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/core/graph.py +32 -25
  9. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/core/pipeline.py +30 -19
  10. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/data_objects/audio.py +8 -5
  11. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/data_objects/curves.py +86 -65
  12. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/data_objects/data.py +16 -14
  13. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/data_objects/image.py +10 -8
  14. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/data_objects/parameters.py +24 -13
  15. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/graphical/gradio_control.py +20 -13
  16. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/graphical/gradio_gui.py +98 -30
  17. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/graphical/gui.py +29 -19
  18. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/graphical/mpl_control.py +27 -11
  19. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/graphical/mpl_gui.py +71 -34
  20. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/graphical/mpl_window.py +17 -3
  21. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/graphical/nb_control.py +42 -14
  22. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/graphical/nb_gui.py +33 -9
  23. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/graphical/qt_control.py +93 -29
  24. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/graphical/qt_gui.py +165 -71
  25. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/graphical/window.py +16 -9
  26. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/headless/control.py +78 -22
  27. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/headless/keyboard.py +44 -11
  28. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/headless/pipeline.py +81 -54
  29. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/helper/choose_backend.py +23 -10
  30. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/helper/control_abbreviation.py +84 -41
  31. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/helper/filter_decorator.py +34 -16
  32. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/helper/keyword_args_analyzer.py +28 -13
  33. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/helper/pipeline_decorator.py +12 -3
  34. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/thirdparty/images_openai_api.py +30 -13
  35. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/thirdparty/music_spotify.py +9 -11
  36. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6/src/interactive_pipe.egg-info}/PKG-INFO +7 -2
  37. interactive_pipe-0.8.6/test/test_cache.py +33 -0
  38. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/test/test_control_abbreviations.py +27 -25
  39. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/test/test_core.py +9 -9
  40. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/test/test_curves.py +33 -23
  41. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/test/test_decorator.py +3 -3
  42. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/test/test_engine.py +31 -26
  43. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/test/test_filter.py +13 -12
  44. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/test/test_headless.py +68 -47
  45. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/test/test_image.py +1 -4
  46. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/test/test_parameters.py +7 -6
  47. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/test/test_recorder.py +17 -11
  48. interactive_pipe-0.8.4/test/test_cache.py +0 -33
  49. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/LICENSE +0 -0
  50. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/setup.cfg +0 -0
  51. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/core/__init__.py +0 -0
  52. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/core/signature.py +0 -0
  53. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/data_objects/__init__.py +0 -0
  54. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/graphical/__init__.py +0 -0
  55. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/headless/__init__.py +0 -0
  56. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/helper/__init__.py +0 -0
  57. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe/helper/_private.py +0 -0
  58. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe.egg-info/SOURCES.txt +0 -0
  59. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe.egg-info/dependency_links.txt +0 -0
  60. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe.egg-info/requires.txt +0 -0
  61. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/src/interactive_pipe.egg-info/top_level.txt +0 -0
  62. {interactive_pipe-0.8.4 → interactive_pipe-0.8.6}/test/test_controller.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: interactive_pipe
3
- Version: 0.8.4
3
+ Version: 0.8.6
4
4
  Summary: Library to create flexible interactive image processing pipelines and automatically add a graphical user interface without knowing anything about GUI coding!
5
5
  Author-email: Balthazar Neveu <balthazarneveu@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/balthazarneveu/interactive_pipe
@@ -106,7 +106,7 @@ pip install -e ".[full]"
106
106
 
107
107
  ## :scroll: Features
108
108
 
109
- **Version 0.8.4**
109
+ **Version 0.8.6**
110
110
  - Modular multi-image processing filters
111
111
  - Declarative: Easily make graphical user interface without having to learn anything about pyQt or matplotlib
112
112
  - Support in jupyter notebooks
@@ -165,6 +165,11 @@ Shortcuts while using the GUI (QT & matplotlib backends)
165
165
  ### [Main tutorial](https://huggingface.co/spaces/balthou/interactive-pipe-tutorial)
166
166
  ![tuto](/doc/images/tutorial.png)
167
167
 
168
+ [Tutorial on Hugging Face space](https://huggingface.co/spaces/balthou/interactive-pipe-tutorial)
169
+
170
+
171
+ [Tutorial in a Colab notebook](https://colab.research.google.com/github/livalgo/interactive-pipe-examples/blob/main/interactive_pipe_tutorial.ipynb#scrollTo=U38Oh7coVKwf)
172
+
168
173
  ### Learn by examples
169
174
  #### [Basic image processing (python code sample for PyQT GUI)](/demo/multi_image.py)
170
175
  | GUI | Pipeline |
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
 
6
6
  [project]
7
7
  name = "interactive_pipe"
8
- version = "0.8.4"
8
+ version = "0.8.6"
9
9
  authors = [
10
10
  { name="Balthazar Neveu", email="balthazarneveu@gmail.com" },
11
11
  ]
@@ -62,7 +62,7 @@ pip install -e ".[full]"
62
62
 
63
63
  ## :scroll: Features
64
64
 
65
- **Version 0.8.4**
65
+ **Version 0.8.6**
66
66
  - Modular multi-image processing filters
67
67
  - Declarative: Easily make graphical user interface without having to learn anything about pyQt or matplotlib
68
68
  - Support in jupyter notebooks
@@ -121,6 +121,11 @@ Shortcuts while using the GUI (QT & matplotlib backends)
121
121
  ### [Main tutorial](https://huggingface.co/spaces/balthou/interactive-pipe-tutorial)
122
122
  ![tuto](/doc/images/tutorial.png)
123
123
 
124
+ [Tutorial on Hugging Face space](https://huggingface.co/spaces/balthou/interactive-pipe-tutorial)
125
+
126
+
127
+ [Tutorial in a Colab notebook](https://colab.research.google.com/github/livalgo/interactive-pipe-examples/blob/main/interactive_pipe_tutorial.ipynb#scrollTo=U38Oh7coVKwf)
128
+
124
129
  ### Learn by examples
125
130
  #### [Basic image processing (python code sample for PyQT GUI)](/demo/multi_image.py)
126
131
  | GUI | Pipeline |
@@ -1,4 +1,4 @@
1
- __version__ = "0.8.4"
1
+ __version__ = "0.8.6"
2
2
  from interactive_pipe.helper.pipeline_decorator import pipeline, interactive_pipeline
3
3
  from interactive_pipe.headless.control import Control, CircularControl, TextPrompt
4
4
  from interactive_pipe.data_objects.curves import Curve, SingleCurve
@@ -48,8 +48,7 @@ class CachedResults:
48
48
  :param new_params: The new parameters to check.
49
49
  :return: True if an update is needed or False otherwise.
50
50
  """
51
- change_state_from_params_check = self.state_change.has_changed(
52
- new_params)
51
+ change_state_from_params_check = self.state_change.has_changed(new_params)
53
52
  if self.force_change:
54
53
  self.state_change.update_needed = True
55
54
  self.force_change = False
@@ -64,8 +63,9 @@ class CachedResults:
64
63
  """
65
64
  if self.name is not None:
66
65
  logging.debug(f"OVERRIDE CACHE RESULTS - {self.name}")
67
- self.result = new_result if not self.safe_buffer_deepcopy else deepcopy(
68
- new_result)
66
+ self.result = (
67
+ new_result if not self.safe_buffer_deepcopy else deepcopy(new_result)
68
+ )
69
69
 
70
70
  def __repr__(self) -> str:
71
71
  return self.name
@@ -106,4 +106,6 @@ class StateChange:
106
106
  self._update_needed = value
107
107
 
108
108
  def __repr__(self) -> str:
109
- return f"{self.name}: " + ("needs update" if self.update_needed else "no update needed")
109
+ return f"{self.name}: " + (
110
+ "needs update" if self.update_needed else "no update needed"
111
+ )
@@ -4,7 +4,6 @@ import time
4
4
  import traceback
5
5
  from copy import deepcopy
6
6
  from typing import List
7
- from interactive_pipe.core.cache import CachedResults
8
7
  from interactive_pipe.core.filter import FilterCore
9
8
 
10
9
 
@@ -22,13 +21,12 @@ class PipelineEngine:
22
21
  for input_index, inp in enumerate(imglst):
23
22
  if self.safe_input_buffer_deepcopy:
24
23
  result[input_index] = deepcopy(inp)
25
- logging.debug(
26
- f"<<< Deepcopy input images {input_index}")
24
+ logging.debug(f"<<< Deepcopy input images {input_index}")
27
25
  else:
28
26
  result[input_index] = inp
29
27
  elif isinstance(imglst, dict):
30
28
  if self.safe_input_buffer_deepcopy:
31
- logging.debug(f"<<< Deepcopy input images")
29
+ logging.debug("<<< Deepcopy input images")
32
30
  result = deepcopy(imglst)
33
31
  else:
34
32
  result = imglst
@@ -43,32 +41,38 @@ class PipelineEngine:
43
41
  # 1 | 0 | True -> cache with no change, skip the calculation
44
42
  # 1 | 1 | False -> cache and result changed, cannot skip so calculate
45
43
  skip_calculation &= (prc.cache_mem is not None) and (
46
- not prc.cache_mem.has_changed(prc.values))
44
+ not prc.cache_mem.has_changed(prc.values)
45
+ )
47
46
 
48
47
  if skip_calculation and self.cache:
49
- logging.debug(
50
- f"--> Load cached outputs from filter {idx}: {prc.name}")
48
+ logging.debug(f"--> Load cached outputs from filter {idx}: {prc.name}")
51
49
  out = prc.cache_mem.result
52
50
  previous_calculation = False
53
51
  else:
54
52
  logging.debug(
55
- ("... " if previous_calculation else "!!! ") + f"Calculating {prc.name}")
53
+ ("... " if previous_calculation else "!!! ")
54
+ + f"Calculating {prc.name}"
55
+ )
56
56
  try:
57
57
  routing_in = []
58
58
  if prc.inputs:
59
59
  routing_in = [
60
- result[idi] if idi is not None else None for idi in prc.inputs]
60
+ result[idi] if idi is not None else None
61
+ for idi in prc.inputs
62
+ ]
61
63
  logging.debug(f"in types-> {[type(inp) for inp in routing_in]}")
62
64
  out = prc.run(*routing_in)
63
65
  if out is not None:
64
66
  logging.debug(f"out types-> {[type(ou) for ou in out]}")
65
67
  except Exception as e:
66
- logging.error(f'Error in {prc.name} filter:')
68
+ logging.error(f"Error in {prc.name} filter:")
67
69
  logging.error(e)
68
70
  traceback.print_exc()
69
71
  sys.exit(1)
70
72
  previous_calculation = True
71
- if self.cache and prc.cache_mem is not None: # cache result if cache available
73
+ if (
74
+ self.cache and prc.cache_mem is not None
75
+ ): # cache result if cache available
72
76
  logging.debug(f"<-- Storing result from {prc.name}")
73
77
  prc.cache_mem.update(out)
74
78
  # put prc output at the right position within result vector
@@ -5,13 +5,28 @@ from typing import Callable, List, Optional, Union, Tuple, Any
5
5
  from interactive_pipe.core.cache import CachedResults
6
6
  from interactive_pipe.core.signature import analyze_apply_fn_signature
7
7
 
8
- EQUIVALENT_STATE_KEYS = ["global_params", "global_parameters", "global_state", "global_context", "context", "state"]
8
+ EQUIVALENT_STATE_KEYS = [
9
+ "global_params",
10
+ "global_parameters",
11
+ "global_state",
12
+ "global_context",
13
+ "context",
14
+ "state",
15
+ ]
9
16
 
10
17
 
11
18
  class PureFilter:
12
- def __init__(self, apply_fn: Optional[Callable] = None, name: Optional[str] = None, default_params: dict = {}):
13
- self.name = name if name else (
14
- self.__class__.__name__ if not apply_fn else apply_fn.__name__)
19
+ def __init__(
20
+ self,
21
+ apply_fn: Optional[Callable] = None,
22
+ name: Optional[str] = None,
23
+ default_params: dict = {},
24
+ ):
25
+ self.name = (
26
+ name
27
+ if name
28
+ else (self.__class__.__name__ if not apply_fn else apply_fn.__name__)
29
+ )
15
30
  if apply_fn is not None:
16
31
  self.apply = apply_fn
17
32
  self._global_params = {}
@@ -34,7 +49,8 @@ class PureFilter:
34
49
  def check_apply_signature(self):
35
50
  if not hasattr(self, "__args_names") or not hasattr(self, "__kwargs_names"):
36
51
  self.__args_names, self.__kwargs_names = analyze_apply_fn_signature(
37
- self.apply)
52
+ self.apply
53
+ )
38
54
  self.signature = (self.__args_names, self.__kwargs_names)
39
55
  else: # skip computing signature
40
56
  pass
@@ -53,8 +69,7 @@ class PureFilter:
53
69
 
54
70
  @values.setter
55
71
  def values(self, new_values):
56
- assert isinstance(
57
- new_values, dict), f"{new_values} is not a dictionary"
72
+ assert isinstance(new_values, dict), f"{new_values} is not a dictionary"
58
73
  self._values = {**self._values, **new_values}
59
74
 
60
75
  def run(self, *imgs) -> Tuple[Any]:
@@ -62,14 +77,16 @@ class PureFilter:
62
77
  assert isinstance(self.values, dict), f"{self.values}"
63
78
  self.check_apply_signature()
64
79
  for key, val in self.values.items():
65
- assert key in self.__kwargs_names.keys(
80
+ assert (
81
+ key in self.__kwargs_names.keys()
66
82
  ), f"{self.name} : {key} not in {self.__kwargs_names.keys()}"
67
83
  global_key_found = False
68
84
  for global_key in EQUIVALENT_STATE_KEYS:
69
85
  if global_key in self.__kwargs_names.keys():
70
86
  # special key to provide the context dictionary
71
87
  out = self.apply(
72
- *imgs, **{**{global_key: self.global_params}, **self.values})
88
+ *imgs, **{**{global_key: self.global_params}, **self.values}
89
+ )
73
90
  global_key_found = True
74
91
  break
75
92
  if not global_key_found:
@@ -80,16 +97,16 @@ class PureFilter:
80
97
  class FilterCore(PureFilter):
81
98
  """PureFilter with cache storage + routing nodes defined (inputs & outputs fields)"""
82
99
 
83
- def __init__(self,
84
- apply_fn: Callable = None,
85
- name: Optional[str] = None,
86
- default_params: dict = {},
87
- inputs: List[Union[int, str]] = [0],
88
- outputs: List[Union[int, str]] = [0],
89
- cache=True,
90
- ):
91
- super().__init__(apply_fn=apply_fn, name=name,
92
- default_params=default_params)
100
+ def __init__(
101
+ self,
102
+ apply_fn: Callable = None,
103
+ name: Optional[str] = None,
104
+ default_params: dict = {},
105
+ inputs: List[Union[int, str]] = [0],
106
+ outputs: List[Union[int, str]] = [0],
107
+ cache=True,
108
+ ):
109
+ super().__init__(apply_fn=apply_fn, name=name, default_params=default_params)
93
110
  self.inputs = inputs
94
111
  self.outputs = outputs
95
112
  self.cache = cache
@@ -104,7 +121,8 @@ class FilterCore(PureFilter):
104
121
  def run(self, *imgs) -> Tuple[Any]:
105
122
  if imgs:
106
123
  assert len(imgs) == len(
107
- self.inputs), "number of inputs shall match what's expected"
124
+ self.inputs
125
+ ), "number of inputs shall match what's expected"
108
126
  if self.inputs is None:
109
127
  if imgs is not None:
110
128
  assert len(imgs) == 0
@@ -116,20 +134,21 @@ class FilterCore(PureFilter):
116
134
  return None
117
135
  if isinstance(out, tuple) or isinstance(out, list):
118
136
  assert len(out) >= len(
119
- self.outputs), "number of outputs shall be at least greater or equal to what's expected by the filter"
137
+ self.outputs
138
+ ), "number of outputs shall be at least greater or equal to what's expected by the filter"
120
139
  return out
121
140
 
122
141
  else:
123
142
  logging.debug(
124
- f"need to return a tuple when you have a single element out {type(out)}")
143
+ f"need to return a tuple when you have a single element out {type(out)}"
144
+ )
125
145
  assert len(self.outputs) == 1, "returning a single element!"
126
146
  return (out,)
127
147
 
128
148
  def __repr__(self) -> str:
129
149
  descr = f"{self.name}: "
130
150
  descr += "(" + (", ".join([f"{it}" for it in self.inputs])) + ")"
131
- descr += " -> " + \
132
- "(" + ", ".join([f"{it}" for it in self.outputs]) + ")"
151
+ descr += " -> " + "(" + ", ".join([f"{it}" for it in self.outputs]) + ")"
133
152
  # descr += "\n"
134
153
  return descr
135
154
 
@@ -1,7 +1,7 @@
1
1
  import ast
2
2
  import inspect
3
3
  import logging
4
- from typing import List, Callable, Tuple, Optional, Union
4
+ from typing import List, Callable, Optional, Union
5
5
  from interactive_pipe.core.filter import FilterCore
6
6
  from interactive_pipe.core.signature import analyze_apply_fn_signature
7
7
 
@@ -17,7 +17,9 @@ def get_name(node: ast.NodeVisitor) -> Union[str, List[str], None]:
17
17
  return None
18
18
 
19
19
 
20
- def flatten_target_names(targets: List[Union[list, str, None]], mapping_function: Optional[Callable] = None) -> List[str]:
20
+ def flatten_target_names(
21
+ targets: List[Union[list, str, None]], mapping_function: Optional[Callable] = None
22
+ ) -> List[str]:
21
23
  output_names = []
22
24
  for target in targets:
23
25
  target_name = mapping_function(target) if mapping_function else target
@@ -42,26 +44,27 @@ def get_call_graph(func: Callable, global_context=None) -> dict:
42
44
  if isinstance(node, ast.Expr) and isinstance(node.value, ast.Call):
43
45
  function_name = get_name(node.value.func)
44
46
  input_names = [get_name(arg) for arg in node.value.args]
45
- results.append({
46
- "function_name": function_name,
47
- "function_object": global_context[function_name],
48
- "args": input_names,
49
- "returns": [],
50
- "output_names": [],
51
- })
47
+ results.append(
48
+ {
49
+ "function_name": function_name,
50
+ "function_object": global_context[function_name],
51
+ "args": input_names,
52
+ "returns": [],
53
+ "output_names": [],
54
+ }
55
+ )
52
56
  logging.debug(f"Function without assignment {function_name}")
53
57
  elif isinstance(node, ast.Assign):
54
58
  targets = node.targets
55
59
  value = node.value
56
60
  if isinstance(value, ast.Call):
57
61
  function_name = get_name(value.func)
58
- logging.debug(
59
- f"classic function with assignment {function_name}")
60
- assert function_name in global_context.keys(
62
+ logging.debug(f"classic function with assignment {function_name}")
63
+ assert (
64
+ function_name in global_context.keys()
61
65
  ), f"Probably mispelled {function_name}"
62
66
  input_names = [get_name(arg) for arg in value.args]
63
- output_names = flatten_target_names(
64
- targets, mapping_function=get_name)
67
+ output_names = flatten_target_names(targets, mapping_function=get_name)
65
68
  function_object = global_context[function_name]
66
69
  if isinstance(function_object, FilterCore):
67
70
  # Case of a filter instance
@@ -79,17 +82,21 @@ def get_call_graph(func: Callable, global_context=None) -> dict:
79
82
  function_apply = global_context[function_name]
80
83
  else:
81
84
  raise TypeError(
82
- f"Not supported {function_name} - should be function or FilterCore")
83
- results.append({
84
- "function_name": function_name,
85
- "function_object": function_apply,
86
- "signature": {"args": sig[0], "kwargs": sig[1]},
87
- "args": input_names,
88
- "returns": output_names,
89
- })
85
+ f"Not supported {function_name} - should be function or FilterCore"
86
+ )
87
+ results.append(
88
+ {
89
+ "function_name": function_name,
90
+ "function_object": function_apply,
91
+ "signature": {"args": sig[0], "kwargs": sig[1]},
92
+ "args": input_names,
93
+ "returns": output_names,
94
+ }
95
+ )
90
96
  main_function = tree.body[0]
91
- outputs = [get_name(ret.value)
92
- for ret in main_function.body if isinstance(ret, ast.Return)]
97
+ outputs = [
98
+ get_name(ret.value) for ret in main_function.body if isinstance(ret, ast.Return)
99
+ ]
93
100
  assert len(outputs) <= 1, "cannot return several times!"
94
101
  outputs = flatten_target_names(outputs, mapping_function=None)
95
102
  inputs, kwargs = analyze_apply_fn_signature(func)
@@ -98,7 +105,7 @@ def get_call_graph(func: Callable, global_context=None) -> dict:
98
105
  "call_graph": results,
99
106
  "args": inputs,
100
107
  "kwargs": kwargs,
101
- "returns": outputs
108
+ "returns": outputs,
102
109
  }
103
110
 
104
111
  return graph
@@ -24,15 +24,17 @@ class PipelineCore:
24
24
  global_context: Optional[dict] = None, # alias for global_params
25
25
  context: Optional[dict] = None, # alias for global_params
26
26
  state: Optional[dict] = None, # alias for global_params
27
- outputs: Optional[list] = None,
28
- safe_input_buffer_deepcopy: bool = True
27
+ outputs: Optional[list] = None,
28
+ safe_input_buffer_deepcopy: bool = True,
29
29
  ):
30
30
  if not all(isinstance(f, FilterCore) for f in filters):
31
31
  raise ValueError(
32
- f"All elements in 'filters' must be instances of 'Filter'. {[type(f) for f in filters]}")
32
+ f"All elements in 'filters' must be instances of 'Filter'. {[type(f) for f in filters]}"
33
+ )
33
34
  self.filters = filters
34
35
  self.engine = PipelineEngine(
35
- cache, safe_input_buffer_deepcopy=safe_input_buffer_deepcopy)
36
+ cache, safe_input_buffer_deepcopy=safe_input_buffer_deepcopy
37
+ )
36
38
  if global_parameters is not None:
37
39
  global_params = global_parameters
38
40
  elif global_context is not None:
@@ -52,7 +54,8 @@ class PipelineCore:
52
54
  self.reset_cache()
53
55
  if inputs is None:
54
56
  logging.warning(
55
- "Setting a pipeline without input - use inputs=[] to get rid of this warning")
57
+ "Setting a pipeline without input - use inputs=[] to get rid of this warning"
58
+ )
56
59
  self.inputs_routing = []
57
60
  else:
58
61
  self.inputs_routing = inputs
@@ -60,8 +63,7 @@ class PipelineCore:
60
63
  self.__initialized_inputs = False
61
64
  if outputs is None:
62
65
  outputs = self.filters[-1].outputs
63
- logging.warning(
64
- f"Using last filter outputs {self.filters[-1]} {outputs}")
66
+ logging.warning(f"Using last filter outputs {self.filters[-1]} {outputs}")
65
67
 
66
68
  self.outputs = outputs # output indexes (routing)
67
69
  # You need to set the values to their default_value for each filter
@@ -74,8 +76,7 @@ class PipelineCore:
74
76
  filter.reset_cache()
75
77
 
76
78
  def run(self) -> list:
77
- """Useful for standalone python acess without gui or disk write
78
- """
79
+ """Useful for standalone python acess without gui or disk write"""
79
80
  return self.engine.run(self.filters, imglst=self.inputs)
80
81
 
81
82
  def _reset_global_params(self):
@@ -110,10 +111,12 @@ class PipelineCore:
110
111
  """
111
112
  available_filters_names = [filt.name for filt in self.filters]
112
113
  for filter_name in new_parameters.keys():
113
- assert filter_name in available_filters_names, f"filter {filter_name}" + \
114
- f"does not exist {available_filters_names}"
115
- self.filters[available_filters_names.index(
116
- filter_name)].values = new_parameters[filter_name]
114
+ assert filter_name in available_filters_names, (
115
+ f"filter {filter_name}" + f"does not exist {available_filters_names}"
116
+ )
117
+ self.filters[available_filters_names.index(filter_name)].values = (
118
+ new_parameters[filter_name]
119
+ )
117
120
 
118
121
  @property
119
122
  def inputs(self):
@@ -126,13 +129,16 @@ class PipelineCore:
126
129
  if isinstance(inputs, dict):
127
130
  provided_keys = list(inputs.keys())
128
131
  for idx, input_name in enumerate(self.inputs_routing):
129
- assert input_name in provided_keys, f"{input_name} is not among {provided_keys}"
132
+ assert (
133
+ input_name in provided_keys
134
+ ), f"{input_name} is not among {provided_keys}"
130
135
  self.__inputs = inputs
131
136
  elif isinstance(inputs, list) or isinstance(inputs, tuple):
132
137
  # inputs is a list or a tuple
133
- assert len(inputs) == len(
134
- self.inputs_routing), f"wrong amount of inputs\nprovided {len(inputs)}" + \
135
- f"inputs vs expected:{len(self.inputs_routing)}"
138
+ assert len(inputs) == len(self.inputs_routing), (
139
+ f"wrong amount of inputs\nprovided {len(inputs)}"
140
+ + f"inputs vs expected:{len(self.inputs_routing)}"
141
+ )
136
142
  self.__inputs = {}
137
143
  for idx, input_name in enumerate(self.inputs_routing):
138
144
  self.__inputs[input_name] = inputs[idx]
@@ -145,8 +151,13 @@ class PipelineCore:
145
151
  # similar to having no input, but explicitly saying that we have initialized it.
146
152
  self.__inputs = None
147
153
  else:
148
- assert self.inputs_routing is None or ((isinstance(self.inputs_routing, tuple) or isinstance(
149
- self.inputs_routing, list)) and len(self.inputs_routing) == 0)
154
+ assert self.inputs_routing is None or (
155
+ (
156
+ isinstance(self.inputs_routing, tuple)
157
+ or isinstance(self.inputs_routing, list)
158
+ )
159
+ and len(self.inputs_routing) == 0
160
+ )
150
161
  self.__inputs = None
151
162
  self.__initialized_inputs = True
152
163
  self.reset_cache()
@@ -5,6 +5,7 @@ from io import BytesIO
5
5
  import base64
6
6
  import logging
7
7
  from typing import Union, Tuple
8
+
8
9
  WAVIO_AVAILABLE = False
9
10
  WAVIO = "wavio"
10
11
  try:
@@ -16,7 +17,9 @@ except ImportError:
16
17
  __iter_audio_player = 0
17
18
 
18
19
 
19
- def audio_to_html(audio: Union[None, str, Path, Tuple[int, np.ndarray]], controls=True) -> str:
20
+ def audio_to_html(
21
+ audio: Union[None, str, Path, Tuple[int, np.ndarray]], controls=True
22
+ ) -> str:
20
23
  if audio is None:
21
24
  logging.debug("No audio to display")
22
25
  return ""
@@ -33,11 +36,11 @@ def audio_to_html(audio: Union[None, str, Path, Tuple[int, np.ndarray]], control
33
36
  audio_base64 = base64.b64encode(audio_bytes.read()).decode("utf-8")
34
37
  audio_player = f'<audio src="data:audio/mpeg;base64,{audio_base64}"'
35
38
  if controls:
36
- audio_player += ' controls'
37
- audio_player += ' autoplay></audio>'
39
+ audio_player += " controls"
40
+ audio_player += " autoplay></audio>"
38
41
  global __iter_audio_player
39
42
  # to avoid reusing the same exact id and thus not updating the audio player
40
- audio_player += "<p hidden>"+str(__iter_audio_player)+"</p>"
43
+ audio_player += "<p hidden>" + str(__iter_audio_player) + "</p>"
41
44
  __iter_audio_player += 1
42
45
 
43
46
  return audio_player
@@ -98,5 +101,5 @@ class Audio(Data):
98
101
 
99
102
 
100
103
  if __name__ == "__main__":
101
- audio_sample_path = Path("demo")/"audio"/"rabbit.mp4"
104
+ audio_sample_path = Path("demo") / "audio" / "rabbit.mp4"
102
105
  rate, data = Audio.load_audio(audio_sample_path)