dotflow 0.8.2.dev1__tar.gz → 0.9.0__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 (59) hide show
  1. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/PKG-INFO +2 -2
  2. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/README.md +1 -1
  3. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/__init__.py +1 -1
  4. dotflow-0.9.0/dotflow/cli/command.py +14 -0
  5. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/cli/commands/__init__.py +2 -2
  6. dotflow-0.9.0/dotflow/cli/commands/init.py +19 -0
  7. dotflow-0.9.0/dotflow/cli/commands/log.py +21 -0
  8. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/cli/commands/start.py +2 -6
  9. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/cli/setup.py +22 -20
  10. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/cli/validators/start.py +1 -1
  11. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/action.py +2 -1
  12. dotflow-0.9.0/dotflow/core/config.py +21 -0
  13. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/decorators/time.py +1 -1
  14. dotflow-0.9.0/dotflow/core/exception.py +53 -0
  15. dotflow-0.9.0/dotflow/core/execution.py +138 -0
  16. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/module.py +3 -1
  17. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/task.py +165 -67
  18. dotflow-0.9.0/dotflow/core/types/__init__.py +10 -0
  19. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/workflow.py +2 -2
  20. dotflow-0.8.2.dev1/dotflow/log.py → dotflow-0.9.0/dotflow/logging.py +6 -6
  21. dotflow-0.9.0/dotflow/settings.py +19 -0
  22. dotflow-0.9.0/dotflow/utils/__init__.py +17 -0
  23. dotflow-0.9.0/dotflow/utils/tools.py +47 -0
  24. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/pyproject.toml +2 -2
  25. dotflow-0.8.2.dev1/dotflow/cli/command.py +0 -10
  26. dotflow-0.8.2.dev1/dotflow/cli/commands/init.py +0 -16
  27. dotflow-0.8.2.dev1/dotflow/cli/commands/server.py +0 -9
  28. dotflow-0.8.2.dev1/dotflow/core/config.py +0 -18
  29. dotflow-0.8.2.dev1/dotflow/core/exception.py +0 -30
  30. dotflow-0.8.2.dev1/dotflow/core/execution.py +0 -86
  31. dotflow-0.8.2.dev1/dotflow/core/models/__init__.py +0 -10
  32. dotflow-0.8.2.dev1/dotflow/core/utils/__init__.py +0 -15
  33. dotflow-0.8.2.dev1/dotflow/core/utils/tools.py +0 -26
  34. dotflow-0.8.2.dev1/dotflow/settings.py +0 -9
  35. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/LICENSE +0 -0
  36. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/abc/__init__.py +0 -0
  37. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/abc/file.py +0 -0
  38. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/abc/http.py +0 -0
  39. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/abc/tcp.py +0 -0
  40. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/cli/__init__.py +0 -0
  41. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/cli/validators/__init__.py +0 -0
  42. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/__init__.py +0 -0
  43. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/context.py +0 -0
  44. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/decorators/__init__.py +0 -0
  45. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/decorators/action.py +0 -0
  46. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/decorators/retry.py +0 -0
  47. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/dotflow.py +0 -0
  48. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/serializers/__init__.py +0 -0
  49. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/serializers/task.py +0 -0
  50. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/serializers/transport.py +0 -0
  51. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/core/serializers/workflow.py +0 -0
  52. {dotflow-0.8.2.dev1/dotflow/core/models → dotflow-0.9.0/dotflow/core/types}/execution.py +0 -0
  53. {dotflow-0.8.2.dev1/dotflow/core/models → dotflow-0.9.0/dotflow/core/types}/status.py +0 -0
  54. {dotflow-0.8.2.dev1/dotflow/core/models → dotflow-0.9.0/dotflow/core/types}/worflow.py +0 -0
  55. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/main.py +0 -0
  56. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/providers/__init__.py +0 -0
  57. {dotflow-0.8.2.dev1 → dotflow-0.9.0}/dotflow/providers/zeromq.py +0 -0
  58. {dotflow-0.8.2.dev1/dotflow/core → dotflow-0.9.0/dotflow}/utils/basic_functions.py +0 -0
  59. {dotflow-0.8.2.dev1/dotflow/core → dotflow-0.9.0/dotflow}/utils/error_handler.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dotflow
3
- Version: 0.8.2.dev1
3
+ Version: 0.9.0
4
4
  Summary: 🎲 Dotflow turns an idea into flow!
5
5
  License: MIT License
6
6
 
@@ -164,7 +164,7 @@ workflow.start()
164
164
  |03| [cli_with_mode](https://github.com/dotflow-io/dotflow/blob/master/examples/cli_with_mode.py) |
165
165
  |04| [cli_with_output_context](https://github.com/dotflow-io/dotflow/blob/master/examples/cli_with_output_context.py) |
166
166
  |05| [cli_with_path](https://github.com/dotflow-io/dotflow/blob/master/examples/cli_with_path.py) |
167
- |06| [cli](https://github.com/dotflow-io/dotflow/blob/master/examples/cli.py) |
167
+ |06| [simple_cli](https://github.com/dotflow-io/dotflow/blob/master/examples/simple_cli.py) |
168
168
  |07| [simple_class_workflow](https://github.com/dotflow-io/dotflow/blob/master/examples/simple_class_workflow.py) |
169
169
  |08| [simple_function_workflow_with_error](https://github.com/dotflow-io/dotflow/blob/master/examples/simple_function_workflow_with_error.py) |
170
170
  |09| [simple_function_workflow](https://github.com/dotflow-io/dotflow/blob/master/examples/simple_function_workflow.py) |
@@ -120,7 +120,7 @@ workflow.start()
120
120
  |03| [cli_with_mode](https://github.com/dotflow-io/dotflow/blob/master/examples/cli_with_mode.py) |
121
121
  |04| [cli_with_output_context](https://github.com/dotflow-io/dotflow/blob/master/examples/cli_with_output_context.py) |
122
122
  |05| [cli_with_path](https://github.com/dotflow-io/dotflow/blob/master/examples/cli_with_path.py) |
123
- |06| [cli](https://github.com/dotflow-io/dotflow/blob/master/examples/cli.py) |
123
+ |06| [simple_cli](https://github.com/dotflow-io/dotflow/blob/master/examples/simple_cli.py) |
124
124
  |07| [simple_class_workflow](https://github.com/dotflow-io/dotflow/blob/master/examples/simple_class_workflow.py) |
125
125
  |08| [simple_function_workflow_with_error](https://github.com/dotflow-io/dotflow/blob/master/examples/simple_function_workflow_with_error.py) |
126
126
  |09| [simple_function_workflow](https://github.com/dotflow-io/dotflow/blob/master/examples/simple_function_workflow.py) |
@@ -1,6 +1,6 @@
1
1
  """Dotflow __init__ module."""
2
2
 
3
- __version__ = "0.8.2.dev1"
3
+ __version__ = "0.9.0"
4
4
  __description__ = "🎲 Dotflow turns an idea into flow!"
5
5
 
6
6
  from .core.config import Config
@@ -0,0 +1,14 @@
1
+ """Command module"""
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+
6
+ class Command(ABC):
7
+
8
+ def __init__(self, **kwargs):
9
+ self.params = kwargs.get("arguments")
10
+ self.setup()
11
+
12
+ @abstractmethod
13
+ def setup(self):
14
+ pass
@@ -1,12 +1,12 @@
1
1
  """Commands __init__ module."""
2
2
 
3
3
  from dotflow.cli.commands.init import InitCommand
4
- from dotflow.cli.commands.server import ServerCommand
4
+ from dotflow.cli.commands.log import LogCommand
5
5
  from dotflow.cli.commands.start import StartCommand
6
6
 
7
7
 
8
8
  __all__ = [
9
9
  "InitCommand",
10
- "ServerCommand",
10
+ "LogCommand",
11
11
  "StartCommand"
12
12
  ]
@@ -0,0 +1,19 @@
1
+ """Command init module"""
2
+
3
+ from os import system
4
+
5
+ from rich import print # type: ignore
6
+
7
+ from dotflow.settings import Settings as settings
8
+ from dotflow.cli.command import Command
9
+
10
+
11
+ class InitCommand(Command):
12
+
13
+ def setup(self):
14
+ if settings.GITIGNORE.exists():
15
+ system("echo '\n\n# Dotflow\n.output' >> .gitignore")
16
+ print(
17
+ settings.INFO_ALERT,
18
+ f"Installation complete! The ({settings.GITIGNORE.resolve()}) file has been modified."
19
+ )
@@ -0,0 +1,21 @@
1
+ """Command log module"""
2
+
3
+ from rich import print # type: ignore
4
+
5
+ from dotflow.utils import read_file
6
+ from dotflow.settings import Settings as settings
7
+ from dotflow.cli.command import Command
8
+
9
+
10
+ class LogCommand(Command):
11
+
12
+ def setup(self):
13
+ if settings.LOG_PATH.exists():
14
+ print(read_file(path=settings.LOG_PATH))
15
+
16
+ print(
17
+ settings.INFO_ALERT,
18
+ f"To access all logs, open the file ({settings.LOG_PATH.resolve()})."
19
+ )
20
+ else:
21
+ print(settings.WARNING_ALERT, "Log file not found.")
@@ -3,17 +3,13 @@
3
3
  from os import system
4
4
 
5
5
  from dotflow import DotFlow, Config
6
- from dotflow.core.models.execution import TypeExecution
6
+ from dotflow.core.types.execution import TypeExecution
7
7
  from dotflow.cli.command import Command
8
8
 
9
9
 
10
10
  class StartCommand(Command):
11
11
 
12
- def __init__(self, **kwargs):
13
- self.params = kwargs.get("arguments")
14
- self.start()
15
-
16
- def start(self):
12
+ def setup(self):
17
13
  workflow = DotFlow(
18
14
  config=Config(
19
15
  path=self.params.path,
@@ -3,17 +3,21 @@
3
3
  from rich import print # type: ignore
4
4
 
5
5
  from dotflow import __version__, __description__
6
- from dotflow.log import logger
6
+ from dotflow.logging import logger
7
7
  from dotflow.settings import Settings as settings
8
- from dotflow.core.utils.basic_functions import basic_callback
9
- from dotflow.core.models.execution import TypeExecution
8
+ from dotflow.utils.basic_functions import basic_callback
9
+ from dotflow.core.types.execution import TypeExecution
10
10
  from dotflow.core.exception import (
11
11
  MissingActionDecorator,
12
12
  ExecutionModeNotExist,
13
13
  ModuleNotFound,
14
14
  MESSAGE_UNKNOWN_ERROR,
15
15
  )
16
- from dotflow.cli.commands import InitCommand, ServerCommand, StartCommand
16
+ from dotflow.cli.commands import (
17
+ InitCommand,
18
+ LogCommand,
19
+ StartCommand
20
+ )
17
21
 
18
22
 
19
23
  class Command:
@@ -32,16 +36,10 @@ class Command:
32
36
  )
33
37
 
34
38
  self.setup_init()
39
+ self.setup_logs()
35
40
  self.setup_start()
36
41
  self.command()
37
42
 
38
- def setup_server(self):
39
- self.cmd_server = self.subparsers.add_parser("server", help="Server")
40
- self.cmd_server = self.cmd_server.add_argument_group(
41
- "Usage: dotflow server [OPTIONS]"
42
- )
43
- self.cmd_server.set_defaults(exec=ServerCommand)
44
-
45
43
  def setup_init(self):
46
44
  self.cmd_init = self.subparsers.add_parser("init", help="Init")
47
45
  self.cmd_init = self.cmd_init.add_argument_group(
@@ -61,7 +59,7 @@ class Command:
61
59
  self.cmd_start.add_argument(
62
60
  "-o", "--output-context", default=False, action="store_true"
63
61
  )
64
- self.cmd_start.add_argument("-p", "--path", default=settings.INITIAL_PATH)
62
+ self.cmd_start.add_argument("-p", "--path", default=settings.START_PATH)
65
63
  self.cmd_start.add_argument(
66
64
  "-m",
67
65
  "--mode",
@@ -71,10 +69,14 @@ class Command:
71
69
 
72
70
  self.cmd_start.set_defaults(exec=StartCommand)
73
71
 
72
+ def setup_logs(self):
73
+ self.cmd_logs = self.subparsers.add_parser("logs", help="Logs")
74
+ self.cmd_logs = self.cmd_logs.add_argument_group(
75
+ "Usage: dotflow log [OPTIONS]"
76
+ )
77
+ self.cmd_logs.set_defaults(exec=LogCommand)
78
+
74
79
  def command(self):
75
- message_icon = ":game_die:"
76
- message_error = "[bold red]Error:[/bold red]"
77
-
78
80
  try:
79
81
  arguments = self.parser.parse_args()
80
82
  if hasattr(arguments, "exec"):
@@ -82,14 +84,14 @@ class Command:
82
84
  else:
83
85
  print(__description__)
84
86
  except MissingActionDecorator as err:
85
- print(message_icon, message_error, err)
87
+ print(settings.WARNING_ALERT, err)
86
88
 
87
89
  except ExecutionModeNotExist as err:
88
- print(message_icon, message_error, err)
90
+ print(settings.WARNING_ALERT, err)
89
91
 
90
92
  except ModuleNotFound as err:
91
- print(message_icon, message_error, err)
93
+ print(settings.WARNING_ALERT, err)
92
94
 
93
95
  except Exception as err:
94
- print(message_icon, message_error, MESSAGE_UNKNOWN_ERROR)
95
- logger.error(err)
96
+ logger.error(f"Internal problem: {str(err)}")
97
+ print(settings.ERROR_ALERT, MESSAGE_UNKNOWN_ERROR)
@@ -13,4 +13,4 @@ class StartValidator(BaseModel):
13
13
  callable: Optional[str] = Field(default=None)
14
14
  initial_context: Optional[str] = Field(default=None)
15
15
  output: Optional[bool] = Field(default=True)
16
- path: Optional[str] = Field(default=settings.INITIAL_PATH)
16
+ path: Optional[str] = Field(default=settings.START_PATH)
@@ -56,7 +56,8 @@ class Action(object):
56
56
 
57
57
  if type(self.func) is type:
58
58
  if hasattr(self.func, "__init__"):
59
- self.params = [param for param in self.func.__init__.__code__.co_varnames]
59
+ if hasattr(self.func.__init__, "__code__"):
60
+ self.params = [param for param in self.func.__init__.__code__.co_varnames]
60
61
 
61
62
  def _get_context(self, kwargs: Dict):
62
63
  context = {}
@@ -0,0 +1,21 @@
1
+ """Config module"""
2
+
3
+ from pathlib import Path
4
+
5
+ from dotflow.settings import Settings as settings
6
+
7
+
8
+ class Config:
9
+
10
+ def __init__(
11
+ self,
12
+ path: str = settings.START_PATH,
13
+ output: bool = False
14
+ ) -> None:
15
+ self.path = Path(path)
16
+ self.task_path = Path(path, "tasks")
17
+ self.log_path = Path(path, settings.LOG_FILE_NAME)
18
+ self.output = output
19
+
20
+ self.path.mkdir(parents=True, exist_ok=True)
21
+ self.task_path.mkdir(parents=True, exist_ok=True)
@@ -7,6 +7,6 @@ def time(func):
7
7
  def inside(*args, **kwargs):
8
8
  start = datetime.now()
9
9
  task = func(*args, **kwargs)
10
- task._set_duration((datetime.now() - start).total_seconds())
10
+ task.duration = (datetime.now() - start).total_seconds()
11
11
  return task
12
12
  return inside
@@ -0,0 +1,53 @@
1
+ """Exception module"""
2
+
3
+ MESSAGE_UNKNOWN_ERROR = "Unknown error, please check logs for more information."
4
+ MESSAGE_MISSING_STEP_DECORATOR = "A step function necessarily needs an '@action' decorator to circulate in the workflow. For more implementation details, access the documentation: https://dotflow-io.github.io/dotflow/nav/getting-started/#3-task-function."
5
+ MESSAGE_NOT_CALLABLE_OBJECT = "Problem validating the '{name}' object type; this is not a callable object"
6
+ MESSAGE_EXECUTION_NOT_EXIST = "The execution mode does not exist. Allowed parameter is 'sequential' and 'background'."
7
+ MESSAGE_MODULE_NOT_FOUND = "Problem importing the python module '{module}'."
8
+ MESSAGE_PROBLEM_ORDERING = "Problem with correctly ordering functions of the '{name}' class."
9
+
10
+ class MissingActionDecorator(Exception):
11
+
12
+ def __init__(self):
13
+ super(MissingActionDecorator, self).__init__(
14
+ MESSAGE_MISSING_STEP_DECORATOR
15
+ )
16
+
17
+
18
+ class ExecutionModeNotExist(Exception):
19
+
20
+ def __init__(self):
21
+ super(ExecutionModeNotExist, self).__init__(
22
+ MESSAGE_EXECUTION_NOT_EXIST
23
+ )
24
+
25
+
26
+ class ModuleNotFound(Exception):
27
+
28
+ def __init__(self, module: str):
29
+ super(ModuleNotFound, self).__init__(
30
+ MESSAGE_MODULE_NOT_FOUND.format(
31
+ module=module
32
+ )
33
+ )
34
+
35
+
36
+ class NotCallableObject(Exception):
37
+
38
+ def __init__(self, name: str):
39
+ super(NotCallableObject, self).__init__(
40
+ MESSAGE_NOT_CALLABLE_OBJECT.format(
41
+ name=name
42
+ )
43
+ )
44
+
45
+
46
+ class ProblemOrdering(Exception):
47
+
48
+ def __init__(self, name: str):
49
+ super(ProblemOrdering, self).__init__(
50
+ MESSAGE_PROBLEM_ORDERING.format(
51
+ name=name
52
+ )
53
+ )
@@ -0,0 +1,138 @@
1
+ """Execution module"""
2
+
3
+ from uuid import UUID
4
+ from typing import Callable, List, Tuple
5
+ from inspect import getsourcelines
6
+ from types import FunctionType, NoneType
7
+
8
+ from dotflow.logging import logger
9
+ from dotflow.core.action import Action
10
+ from dotflow.core.context import Context
11
+ from dotflow.core.task import Task
12
+ from dotflow.core.types import TaskStatus
13
+
14
+ from dotflow.core.decorators import time
15
+
16
+
17
+ class Execution:
18
+
19
+ VALID_OBJECTS = [
20
+ str,
21
+ int,
22
+ float,
23
+ dict,
24
+ list,
25
+ tuple,
26
+ set,
27
+ bool,
28
+ FunctionType,
29
+ NoneType
30
+ ]
31
+
32
+ def __init__(
33
+ self,
34
+ task: Task,
35
+ workflow_id: UUID,
36
+ previous_context: Context
37
+ ) -> None:
38
+ self.task = task
39
+ self.task.status = TaskStatus.IN_PROGRESS
40
+ self.task.previous_context = previous_context
41
+ self.task.workflow_id = workflow_id
42
+
43
+ self._excution()
44
+
45
+ def _is_action(self, class_instance: Callable, func: Callable):
46
+ return (
47
+ callable(getattr(class_instance, func))
48
+ and not func.startswith("__")
49
+ and getattr(class_instance, func).__module__ is Action.__module__
50
+ )
51
+
52
+ def _execution_orderer(
53
+ self,
54
+ callable_list: List[str],
55
+ class_instance: Callable
56
+ ) -> Tuple[int, Callable]:
57
+ ordered_list = []
58
+
59
+ try:
60
+ inside_code = getsourcelines(class_instance.__class__)[0]
61
+
62
+ for callable_name in callable_list:
63
+ for index, code in enumerate(inside_code):
64
+ if code.find(f"def {callable_name}") != -1:
65
+ ordered_list.append((index, callable_name))
66
+
67
+ ordered_list.sort()
68
+ return ordered_list
69
+
70
+ except TypeError as err:
71
+ logger.error(f"Internal problem: {str(err)}")
72
+
73
+ for index, callable_name in enumerate(callable_list):
74
+ ordered_list.append((index, callable_name))
75
+
76
+ return ordered_list
77
+
78
+ def _execution_with_class(self, class_instance: Callable):
79
+ new_context = Context(storage=[])
80
+ previous_context = self.task.previous_context
81
+ callable_list = [
82
+ func
83
+ for func in dir(class_instance)
84
+ if self._is_action(class_instance, func)
85
+ ]
86
+
87
+ ordered_list = self._execution_orderer(
88
+ callable_list=callable_list, class_instance=class_instance
89
+ )
90
+
91
+ for _, new in ordered_list:
92
+ new_object = getattr(class_instance, new)
93
+ try:
94
+ subcontext = new_object(
95
+ initial_context=self.task.initial_context,
96
+ previous_context=previous_context,
97
+ )
98
+ new_context.storage.append(subcontext)
99
+ previous_context = subcontext
100
+
101
+ except Exception:
102
+ subcontext = new_object(
103
+ class_instance,
104
+ initial_context=self.task.initial_context,
105
+ previous_context=previous_context,
106
+ )
107
+ new_context.storage.append(subcontext)
108
+ previous_context = subcontext
109
+
110
+ if not new_context.storage:
111
+ return Context(storage=class_instance)
112
+
113
+ return new_context
114
+
115
+ @time
116
+ def _excution(self):
117
+ try:
118
+ current_context = self.task.step(
119
+ initial_context=self.task.initial_context,
120
+ previous_context=self.task.previous_context,
121
+ )
122
+
123
+ if type(current_context.storage) not in self.VALID_OBJECTS:
124
+ current_context = self._execution_with_class(
125
+ class_instance=current_context.storage
126
+ )
127
+
128
+ self.task.status = TaskStatus.COMPLETED
129
+ self.task.current_context = current_context
130
+
131
+ except Exception as err:
132
+ self.task.status = TaskStatus.FAILED
133
+ self.task.error = err
134
+
135
+ finally:
136
+ self.task.callback(content=self.task)
137
+
138
+ return self.task
@@ -30,7 +30,9 @@ class Module:
30
30
  if hasattr(module, cls._get_name(value)):
31
31
  return getattr(module, cls._get_name(value))
32
32
 
33
- raise ModuleNotFound()
33
+ raise ModuleNotFound(
34
+ module=value
35
+ )
34
36
 
35
37
  @classmethod
36
38
  def _get_name(cls, value: str):