fabricatio 0.2.0.dev1__py3-none-any.whl → 0.2.0.dev2__py3-none-any.whl

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.
fabricatio/__init__.py CHANGED
@@ -1,24 +1,32 @@
1
1
  """Fabricatio is a Python library for building llm app using event-based agent structure."""
2
2
 
3
3
  from fabricatio.core import env
4
+ from fabricatio.fs import magika
4
5
  from fabricatio.journal import logger
5
6
  from fabricatio.models.action import Action, WorkFlow
6
7
  from fabricatio.models.events import Event
7
8
  from fabricatio.models.role import Role
8
9
  from fabricatio.models.task import Task
9
10
  from fabricatio.models.tool import ToolBox
10
- from fabricatio.models.utils import Messages
11
- from fabricatio.parser import Capture
11
+ from fabricatio.models.utils import Message, Messages
12
+ from fabricatio.parser import Capture, CodeBlockCapture, JsonCapture, PythonCapture
13
+ from fabricatio.templates import templates_manager
12
14
 
13
15
  __all__ = [
14
16
  "Action",
15
17
  "Capture",
18
+ "CodeBlockCapture",
16
19
  "Event",
20
+ "JsonCapture",
21
+ "Message",
17
22
  "Messages",
23
+ "PythonCapture",
18
24
  "Role",
19
25
  "Task",
20
26
  "ToolBox",
21
27
  "WorkFlow",
22
28
  "env",
23
29
  "logger",
30
+ "magika",
31
+ "templates_manager",
24
32
  ]
@@ -0,0 +1,13 @@
1
+ from fabricatio.models.action import Action
2
+ from fabricatio.models.task import Task
3
+
4
+
5
+ class Talk(Action):
6
+ """Action that says hello to the world."""
7
+
8
+ name: str = "talk"
9
+ output_key: str = "talk_response"
10
+
11
+ async def _execute(self, task_input: Task[str], **_) -> str:
12
+ """Execute the action."""
13
+ return await self.aask(task_input.briefing, system_message=task_input.generate_prompt())
@@ -12,9 +12,21 @@ class PublishTask(Action):
12
12
  name: str = "publish_task"
13
13
  """The name of the action."""
14
14
  description: str = "Publish a task to a list of targets."
15
+ """The description of the action."""
15
16
 
16
17
  async def _execute(self, send_targets: List[EventLike], send_task: Task, **_) -> None:
17
18
  """Execute the action by sending the task to the specified targets."""
18
19
  logger.info(f"Sending task {send_task.name} to {send_targets}")
19
20
  for target in send_targets:
20
21
  await send_task.move_to(target).publish()
22
+
23
+
24
+ class CycleTask(Action):
25
+ """An action that cycles a task through a list of targets."""
26
+
27
+ name: str = "cycle_task"
28
+ """The name of the action."""
29
+ description: str = "Cycle a task through a list of targets"
30
+
31
+ async def _execute(self, task_input: Task, **_) -> None:
32
+ """Execute the action by cycling the task through the specified targets."""
@@ -0,0 +1,92 @@
1
+ import shutil
2
+ import subprocess
3
+ import tarfile
4
+ from pathlib import Path
5
+
6
+ import requests
7
+ import typer
8
+
9
+ app = typer.Typer()
10
+
11
+
12
+ def download_file(url: str, destination: Path) -> None:
13
+ """Download a file from a given URL to a specified destination.
14
+
15
+ Args:
16
+ url (str): The URL of the file to download.
17
+ destination (Path): The path where the file should be saved.
18
+
19
+ Raises:
20
+ requests.exceptions.HTTPError: If the request to the URL fails.
21
+ """
22
+ response = requests.get(url, stream=True, timeout=120)
23
+ response.raise_for_status()
24
+ with destination.open("wb") as f:
25
+ for chunk in response.iter_content(chunk_size=8192):
26
+ f.write(chunk)
27
+
28
+
29
+ def extract_tar_gz(file_path: Path, extract_to: Path) -> None:
30
+ """Extract a tar.gz file to a specified directory.
31
+
32
+ Args:
33
+ file_path (Path): The path to the tar.gz file.
34
+ extract_to (Path): The directory where the contents should be extracted.
35
+ """
36
+ with tarfile.open(file_path, "r:gz") as tar:
37
+ tar.extractall(path=extract_to, filter="data")
38
+
39
+
40
+ def extract_with_7z(file_path: Path, extract_to: Path) -> None:
41
+ """Extract a file using the 7z command-line tool.
42
+
43
+ Args:
44
+ file_path (Path): The path to the file to extract.
45
+ extract_to (Path): The directory where the contents should be extracted.
46
+
47
+ Raises:
48
+ subprocess.CalledProcessError: If the 7z command fails.
49
+ """
50
+ subprocess.run(["7z", "x", file_path, f"-o{extract_to}"], check=True)
51
+
52
+
53
+ @app.command()
54
+ def download_and_extract(output_dir: str = typer.Argument(..., help="Directory to extract the templates to")) -> None:
55
+ """Download and extract the templates.tar.gz file from the latest release of the fabricatio GitHub repository.
56
+
57
+ Args:
58
+ output_dir (str): The directory where the templates should be extracted.
59
+
60
+ Raises:
61
+ typer.Exit: If the templates.tar.gz file is not found or extraction fails.
62
+ """
63
+ repo_url = "https://api.github.com/repos/Whth/fabricatio/releases/latest"
64
+ response = requests.get(repo_url, timeout=30)
65
+ response.raise_for_status()
66
+ latest_release = response.json()
67
+ assets = latest_release.get("assets", [])
68
+ tar_gz_asset = next((asset for asset in assets if asset["name"] == "templates.tar.gz"), None)
69
+
70
+ if not tar_gz_asset:
71
+ typer.echo("templates.tar.gz not found in the latest release.")
72
+ raise typer.Exit(code=1)
73
+
74
+ download_url = tar_gz_asset["browser_download_url"]
75
+ output_path = Path(output_dir) # Convert output_dir to Path object
76
+ tar_gz_path = output_path.joinpath("templates.tar.gz") # Use joinpath instead of os.path.join
77
+
78
+ download_file(download_url, tar_gz_path) # Directly use Path object
79
+ typer.echo(f"Downloaded {download_url} to {tar_gz_path}")
80
+
81
+ try:
82
+ if shutil.which("7z"):
83
+ extract_with_7z(tar_gz_path, output_path) # Directly use Path objects
84
+ elif shutil.which("tar"):
85
+ extract_tar_gz(tar_gz_path, output_path) # Directly use Path objects
86
+ else:
87
+ typer.echo("Neither 7z nor tar is available for extraction.")
88
+ raise typer.Exit(code=1)
89
+ typer.echo(f"Extracted templates to {output_dir}")
90
+ except RuntimeError as e:
91
+ typer.echo(f"Extraction failed: {e}")
92
+ raise typer.Exit(code=1) from e
fabricatio/config.py CHANGED
@@ -1,3 +1,4 @@
1
+ from pathlib import Path
1
2
  from typing import List, Literal, Optional
2
3
 
3
4
  from appdirs import user_config_dir
@@ -119,10 +120,13 @@ class Code2PromptConfig(BaseModel):
119
120
 
120
121
  model_config = ConfigDict(use_attribute_docstrings=True)
121
122
  template_dir: List[DirectoryPath] = Field(
122
- default_factory=lambda: [r".\c2p_templates", rf"{ROAMING_DIR}\c2p_templates"]
123
+ default_factory=lambda: [Path(r".\templates"), Path(rf"{ROAMING_DIR}\templates")]
123
124
  )
124
125
  """The directory containing the templates for code2prompt."""
125
126
 
127
+ template_suffix: str = Field(default=".hbs", frozen=True)
128
+ """The suffix of the template files for code2prompt."""
129
+
126
130
 
127
131
  class MagikaConfig(BaseModel):
128
132
  """Magika configuration class."""
fabricatio/fs/__init__.py CHANGED
@@ -1 +1,5 @@
1
1
  """FileSystem manipulation module for Fabricatio."""
2
+
3
+ from fabricatio.fs.readers import magika
4
+
5
+ __all__ = ["magika"]
@@ -1,20 +1,22 @@
1
1
  import traceback
2
2
  from abc import abstractmethod
3
3
  from asyncio import Queue
4
- from typing import Any, Dict, Tuple, Type, Unpack
4
+ from typing import Any, Dict, Self, Tuple, Type, Unpack
5
5
 
6
6
  from pydantic import Field, PrivateAttr
7
7
 
8
8
  from fabricatio.journal import logger
9
9
  from fabricatio.models.generic import LLMUsage, WithBriefing
10
- from fabricatio.models.task import Task
10
+ from fabricatio.models.task import ProposeTask, Task
11
11
 
12
12
 
13
- class Action(WithBriefing, LLMUsage):
13
+ class Action(ProposeTask):
14
14
  """Class that represents an action to be executed in a workflow."""
15
15
 
16
+ personality: str = Field(default="")
17
+ """The personality of whom the action belongs to."""
16
18
  output_key: str = Field(default="")
17
- """ The key of the output data."""
19
+ """The key of the output data."""
18
20
 
19
21
  @abstractmethod
20
22
  async def _execute(self, **cxt: Unpack) -> Any:
@@ -40,6 +42,12 @@ class Action(WithBriefing, LLMUsage):
40
42
  cxt[self.output_key] = ret
41
43
  return cxt
42
44
 
45
+ def briefing(self) -> str:
46
+ """Return a brief description of the action."""
47
+ if self.personality:
48
+ return f"## Your personality: \n{self.personality}\n# The action you are going to perform: \n{super().briefing}"
49
+ return f"# The action you are going to perform: \n{super().briefing}"
50
+
43
51
 
44
52
  class WorkFlow[A: Type[Action] | Action](WithBriefing, LLMUsage):
45
53
  """Class that represents a workflow to be executed in a task."""
@@ -48,6 +56,7 @@ class WorkFlow[A: Type[Action] | Action](WithBriefing, LLMUsage):
48
56
  """ The context dictionary to be used for workflow execution."""
49
57
 
50
58
  _instances: Tuple[Action, ...] = PrivateAttr(...)
59
+ """ The instances of the workflow steps."""
51
60
 
52
61
  steps: Tuple[A, ...] = Field(...)
53
62
  """ The steps to be executed in the workflow, actions or action classes."""
@@ -69,8 +78,19 @@ class WorkFlow[A: Type[Action] | Action](WithBriefing, LLMUsage):
69
78
  temp.append(step if isinstance(step, Action) else step())
70
79
  self._instances = tuple(temp)
71
80
 
72
- for step in self._instances:
73
- step.fallback_to(self)
81
+ def inject_personality(self, personality: str) -> Self:
82
+ """Inject the personality of the workflow.
83
+
84
+ Args:
85
+ personality: The personality to be injected.
86
+
87
+ Returns:
88
+ Self: The instance of the workflow with the injected personality.
89
+ """
90
+ for a in self._instances:
91
+ if not a.personality:
92
+ a.personality = personality
93
+ return self
74
94
 
75
95
  async def serve(self, task: Task) -> None:
76
96
  """Serve the task by executing the workflow steps.
@@ -99,3 +119,9 @@ class WorkFlow[A: Type[Action] | Action](WithBriefing, LLMUsage):
99
119
  """Initialize the context dictionary for workflow execution."""
100
120
  logger.debug(f"Initializing context for workflow: {self.name}")
101
121
  await self._context.put({self.task_input_key: None, **dict(self.extra_init_context)})
122
+
123
+ def fallback_to_self(self) -> Self:
124
+ """Set the fallback for each step to the workflow itself."""
125
+ for step in self._instances:
126
+ step.fallback_to(self)
127
+ return self
fabricatio/models/role.py CHANGED
@@ -1,17 +1,15 @@
1
1
  from typing import Any
2
2
 
3
- from pydantic import Field, ValidationError
3
+ from pydantic import Field
4
4
 
5
5
  from fabricatio.core import env
6
6
  from fabricatio.journal import logger
7
7
  from fabricatio.models.action import WorkFlow
8
8
  from fabricatio.models.events import Event
9
- from fabricatio.models.generic import LLMUsage, Memorable, WithBriefing, WithToDo
10
- from fabricatio.models.task import Task
11
- from fabricatio.parser import JsonCapture
9
+ from fabricatio.models.task import ProposeTask
12
10
 
13
11
 
14
- class Role(Memorable, WithBriefing, WithToDo, LLMUsage):
12
+ class Role(ProposeTask):
15
13
  """Class that represents a role with a registry of events and workflows."""
16
14
 
17
15
  registry: dict[Event | str, WorkFlow] = Field(...)
@@ -20,31 +18,8 @@ class Role(Memorable, WithBriefing, WithToDo, LLMUsage):
20
18
  def model_post_init(self, __context: Any) -> None:
21
19
  """Register the workflows in the role to the event bus."""
22
20
  for event, workflow in self.registry.items():
23
- workflow.fallback_to(self)
21
+ workflow.fallback_to(self).fallback_to_self().inject_personality(self.briefing)
24
22
  logger.debug(
25
23
  f"Registering workflow: {workflow.name} for event: {event.collapse() if isinstance(event, Event) else event}"
26
24
  )
27
25
  env.on(event, workflow.serve)
28
-
29
- async def propose(self, prompt: str) -> Task:
30
- """Propose a task based on the provided prompt."""
31
- assert prompt, "Prompt must be provided."
32
-
33
- def _validate_json(response: str) -> None | Task:
34
- try:
35
- cap = JsonCapture.capture(response)
36
- logger.debug(f"Response: \n{response}")
37
- logger.info(f"Captured JSON: \n{cap[0]}")
38
- return Task.model_validate_json(cap[0] if cap else response)
39
- except ValidationError as e:
40
- logger.error(f"Failed to parse task from JSON: {e}")
41
- return None
42
-
43
- return await self.aask_validate(
44
- f"{prompt} \n\nBased on requirement above, "
45
- f"you need to construct a task to satisfy that requirement in JSON format "
46
- f"written like this: \n\n```json\n{Task.json_example()}\n```\n\n"
47
- f"No extra explanation needed. ",
48
- _validate_json,
49
- system_message=f"# your personal briefing: \n{self.briefing}",
50
- )
fabricatio/models/task.py CHANGED
@@ -7,12 +7,13 @@ from asyncio import Queue
7
7
  from enum import Enum
8
8
  from typing import Any, List, Optional, Self
9
9
 
10
- from pydantic import Field, PrivateAttr
10
+ from pydantic import Field, PrivateAttr, ValidationError
11
11
 
12
12
  from fabricatio.core import env
13
13
  from fabricatio.journal import logger
14
14
  from fabricatio.models.events import Event, EventLike
15
- from fabricatio.models.generic import WithBriefing, WithDependency, WithJsonExample
15
+ from fabricatio.models.generic import LLMUsage, WithBriefing, WithDependency, WithJsonExample
16
+ from fabricatio.parser import JsonCapture
16
17
 
17
18
 
18
19
  class TaskStatus(Enum):
@@ -254,3 +255,30 @@ class Task[T](WithBriefing, WithJsonExample, WithDependency):
254
255
  str: The briefing of the task.
255
256
  """
256
257
  return f"{super().briefing}\n{self.goal}"
258
+
259
+
260
+ class ProposeTask(LLMUsage, WithBriefing):
261
+ """A class that proposes a task based on a prompt."""
262
+
263
+ async def propose(self, prompt: str) -> Task:
264
+ """Propose a task based on the provided prompt."""
265
+ assert prompt, "Prompt must be provided."
266
+
267
+ def _validate_json(response: str) -> None | Task:
268
+ try:
269
+ cap = JsonCapture.capture(response)
270
+ logger.debug(f"Response: \n{response}")
271
+ logger.info(f"Captured JSON: \n{cap[0]}")
272
+ return Task.model_validate_json(cap[0] if cap else response)
273
+ except ValidationError as e:
274
+ logger.error(f"Failed to parse task from JSON: {e}")
275
+ return None
276
+
277
+ return await self.aask_validate(
278
+ f"{prompt} \n\nBased on requirement above, "
279
+ f"you need to construct a task to satisfy that requirement in JSON format "
280
+ f"written like this: \n\n```json\n{Task.json_example()}\n```\n\n"
281
+ f"No extra explanation needed. ",
282
+ _validate_json,
283
+ system_message=f"# your personal briefing: \n{self.briefing}",
284
+ )
fabricatio/models/tool.py CHANGED
@@ -24,7 +24,7 @@ class Tool[**P, R](WithBriefing):
24
24
  assert self.name, "The tool must have a name."
25
25
  self.description = self.description or self.source.__doc__ or ""
26
26
 
27
- def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
27
+ def invoke(self, *args: P.args, **kwargs: P.kwargs) -> R:
28
28
  """Invoke the tool's source function with the provided arguments."""
29
29
  return self.source(*args, **kwargs)
30
30
 
@@ -82,20 +82,18 @@ class ToolBox(WithBriefing):
82
82
  toc = f"## {self.name}: {self.description}\n## {len(self.tools)} tools available:"
83
83
  return f"{toc}\n\n{list_out}"
84
84
 
85
- def invoke_tool[**P, R](self, name: str, *args: P.args, **kwargs: P.kwargs) -> R:
85
+ def get[**P, R](self, name: str) -> Tool[P, R]:
86
86
  """Invoke a tool by name with the provided arguments.
87
87
 
88
88
  Args:
89
89
  name (str): The name of the tool to invoke.
90
- *args (P.args): Positional arguments to pass to the tool.
91
- **kwargs (P.kwargs): Keyword arguments to pass to the tool.
92
90
 
93
91
  Returns:
94
- R: The result of the tool's execution.
92
+ Tool: The tool instance with the specified name.
95
93
 
96
94
  Raises:
97
95
  AssertionError: If no tool with the specified name is found.
98
96
  """
99
97
  tool = next((tool for tool in self.tools if tool.name == name), None)
100
98
  assert tool, f"No tool named {name} found."
101
- return tool(*args, **kwargs)
99
+ return tool
@@ -0,0 +1,39 @@
1
+ from typing import Any, Dict, List, Self
2
+
3
+ from pydantic import BaseModel, ConfigDict, DirectoryPath, Field, FilePath, PrivateAttr
4
+
5
+ from fabricatio.config import configs
6
+ from fabricatio.journal import logger
7
+
8
+
9
+ class TemplateManager(BaseModel):
10
+ """A class that manages templates for code generation."""
11
+
12
+ model_config = ConfigDict(use_attribute_docstrings=True)
13
+ templates_dir: List[DirectoryPath] = Field(default_factory=lambda: list(configs.code2prompt.template_dir))
14
+ """The directories containing the templates. first element has the highest override priority."""
15
+ _discovered_templates: Dict[str, FilePath] = PrivateAttr(default_factory=dict)
16
+
17
+ def model_post_init(self, __context: Any) -> None:
18
+ """Post-initialization method for the model."""
19
+ self.discover_templates()
20
+
21
+ def discover_templates(self) -> Self:
22
+ """Discover the templates in the template directories."""
23
+ discovered = [
24
+ f
25
+ for d in self.templates_dir[::-1]
26
+ for f in d.rglob(f"*{configs.code2prompt.template_suffix}", case_sensitive=False)
27
+ if f.is_file()
28
+ ]
29
+
30
+ self._discovered_templates = {f.stem: f for f in discovered}
31
+ logger.info(f"Discovered {len(self._discovered_templates)} templates.")
32
+ return self
33
+
34
+ def get_template(self, name: str) -> FilePath | None:
35
+ """Get the template with the specified name."""
36
+ return self._discovered_templates.get(name, None)
37
+
38
+
39
+ templates_manager = TemplateManager()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fabricatio
3
- Version: 0.2.0.dev1
3
+ Version: 0.2.0.dev2
4
4
  Summary: A LLM multi-agent framework.
5
5
  Author-email: Whth <zettainspector@foxmail.com>
6
6
  License: MIT License
@@ -43,12 +43,14 @@ Requires-Dist: litellm>=1.60.0
43
43
  Requires-Dist: loguru>=0.7.3
44
44
  Requires-Dist: magika>=0.5.1
45
45
  Requires-Dist: orjson>=3.10.15
46
+ Requires-Dist: pybars3>=0.9.7
46
47
  Requires-Dist: pydantic-settings>=2.7.1
47
48
  Requires-Dist: pydantic>=2.10.6
48
49
  Requires-Dist: pymitter>=1.0.0
49
50
  Requires-Dist: questionary>=2.1.0
50
51
  Requires-Dist: regex>=2024.11.6
51
52
  Requires-Dist: rich>=13.9.4
53
+ Requires-Dist: typer>=0.15.1
52
54
  Description-Content-Type: text/markdown
53
55
 
54
56
  # Fabricatio
@@ -0,0 +1,28 @@
1
+ fabricatio/__init__.py,sha256=eznZiLDVe3pw0NwX36Rari-DK0zxDTpa_wwAmWGnto8,909
2
+ fabricatio/config.py,sha256=61wo7pingdp8vaxzI78QLSLWtuTdMbsa0FgOTJbnnZM,7979
3
+ fabricatio/core.py,sha256=B6KBIfBRF023HF0UUaUprEkQd6sT7G_pexGXQ9btJnE,5788
4
+ fabricatio/decorators.py,sha256=Qsyb-_cDwtXY5yhyLrYZEAlrHh5ZuEooQ8vEOUAxj8k,1855
5
+ fabricatio/journal.py,sha256=CW9HePtgTiboOyPTExq9GjG5BseZcbc-S6lxDXrpmv0,667
6
+ fabricatio/parser.py,sha256=6PNFNNyHNkNG7vTS1ejFc4vCzl1OCy4bqB0e4Ty_-Qs,2365
7
+ fabricatio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ fabricatio/templates.py,sha256=7HnWGp2a_Z4ILBHb0Hxh0sOBs8fVD8V6wsnb_OIkYww,1553
9
+ fabricatio/actions/__init__.py,sha256=eFmFVPQvtNgFynIXBVr3eP-vWQDWCPng60YY5LXvZgg,115
10
+ fabricatio/actions/communication.py,sha256=tmsr3H_w-V-b2WxLEyWByGuwSCLgHIHTdHYAgHrdUxc,425
11
+ fabricatio/actions/transmission.py,sha256=PedZ6XsflKdT5ikzaqWr_6h8jci0kekAHfwygzKBUns,1188
12
+ fabricatio/bin/template_download.py,sha256=JcertOKBIHHorXrQURdqH2wgy2LLzqps5ADp7QbYNgc,3415
13
+ fabricatio/fs/__init__.py,sha256=lWcKYg0v3mv2LnnSegOQaTtlVDODU0vtw_s6iKU5IqQ,122
14
+ fabricatio/fs/readers.py,sha256=mw0VUH3P7Wk0SMlcQm2yOfjEz5C3mQ_kjduAjecaxgY,123
15
+ fabricatio/models/action.py,sha256=M5EfKRJr6puUeKPMm8SGxtKIQWcDcR6dZYs1VTN0ihw,4977
16
+ fabricatio/models/events.py,sha256=pW3sfxEFWTafbP4bn4hVFSe8qloYrrzOgi9oMCqAEgw,2604
17
+ fabricatio/models/generic.py,sha256=noHow8dUjMnNiasl2ZHaZeCMpxzDme9QvxTetoyB45w,19539
18
+ fabricatio/models/role.py,sha256=PM4yBMkHIjYVGsUKlWFbKSOUnhJ8pMXSBySG3Ub4e60,972
19
+ fabricatio/models/task.py,sha256=VPK7ey5AFTeH_Ufr-qwDXEhdwA6GRfBElLIiVH6azDA,9431
20
+ fabricatio/models/tool.py,sha256=1hxDvE92uiWCaxrb0c81EGCkNrt8Ce_V9JDBz7b3qVo,3349
21
+ fabricatio/models/utils.py,sha256=2mgXla9_K3dnRrz6hIKzmltTYPmvDk0MBjjEBkCXTdg,2474
22
+ fabricatio/toolboxes/__init__.py,sha256=bjefmPd7wBaWhbZzdMPXvrjMTeRzlUh_Dev2PUAc124,158
23
+ fabricatio/toolboxes/task.py,sha256=xgyPetm2R_HlQwpzE8YPnBN7QOYLd0-T8E6QPZG1PPQ,204
24
+ fabricatio-0.2.0.dev2.dist-info/METADATA,sha256=7sQ65HU4g26s-Vd1dXOUTQ0bygyZPU9eLTsfgOs1jZc,7113
25
+ fabricatio-0.2.0.dev2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
26
+ fabricatio-0.2.0.dev2.dist-info/entry_points.txt,sha256=qfO9AWRzHvppZwBQ9LKc88-Y9jf2o_0rqEEnM7daM-8,84
27
+ fabricatio-0.2.0.dev2.dist-info/licenses/LICENSE,sha256=do7J7EiCGbq0QPbMAL_FqLYufXpHnCnXBOuqVPwSV8Y,1088
28
+ fabricatio-0.2.0.dev2.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ templates = fabricatio.bin.template_download:download_and_extract
@@ -1,24 +0,0 @@
1
- fabricatio/__init__.py,sha256=nFPtohqceECRYzU-WlVT6o4oSaKN0vGok-w9JIaiJfs,644
2
- fabricatio/config.py,sha256=emkIpaXRQykAX_C2ND8tKR2DQUJJEN0mvdMDTklwOXw,7823
3
- fabricatio/core.py,sha256=B6KBIfBRF023HF0UUaUprEkQd6sT7G_pexGXQ9btJnE,5788
4
- fabricatio/decorators.py,sha256=Qsyb-_cDwtXY5yhyLrYZEAlrHh5ZuEooQ8vEOUAxj8k,1855
5
- fabricatio/journal.py,sha256=CW9HePtgTiboOyPTExq9GjG5BseZcbc-S6lxDXrpmv0,667
6
- fabricatio/parser.py,sha256=6PNFNNyHNkNG7vTS1ejFc4vCzl1OCy4bqB0e4Ty_-Qs,2365
7
- fabricatio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- fabricatio/actions/__init__.py,sha256=eFmFVPQvtNgFynIXBVr3eP-vWQDWCPng60YY5LXvZgg,115
9
- fabricatio/actions/transmission.py,sha256=TABvBB127hC3KYvm7zJp_i-_GF9wXXCR-k8bxfhNYak,768
10
- fabricatio/fs/__init__.py,sha256=OL9f4jZDYcErSM7Yw7rhy97f8QDE-6wZIoGz1reS3Z0,54
11
- fabricatio/fs/readers.py,sha256=mw0VUH3P7Wk0SMlcQm2yOfjEz5C3mQ_kjduAjecaxgY,123
12
- fabricatio/models/action.py,sha256=CbGuR9dHnu87MFAzLWj8cVHZtFNyT_VuwT3pWlKJvEk,3925
13
- fabricatio/models/events.py,sha256=pW3sfxEFWTafbP4bn4hVFSe8qloYrrzOgi9oMCqAEgw,2604
14
- fabricatio/models/generic.py,sha256=noHow8dUjMnNiasl2ZHaZeCMpxzDme9QvxTetoyB45w,19539
15
- fabricatio/models/role.py,sha256=jdabuYRXwgvpYoNwvazygDiZHGGQApUIIKltniu78O8,2151
16
- fabricatio/models/task.py,sha256=mWIQHdi1mNJlER5ZFeywsZxg4Skm-VnjW2z8ZEMJLNE,8190
17
- fabricatio/models/tool.py,sha256=UkEp1Nzbl5wZX21q_Z2VkpiJmVDSdoGDzINQniO8hSY,3536
18
- fabricatio/models/utils.py,sha256=2mgXla9_K3dnRrz6hIKzmltTYPmvDk0MBjjEBkCXTdg,2474
19
- fabricatio/toolboxes/__init__.py,sha256=bjefmPd7wBaWhbZzdMPXvrjMTeRzlUh_Dev2PUAc124,158
20
- fabricatio/toolboxes/task.py,sha256=xgyPetm2R_HlQwpzE8YPnBN7QOYLd0-T8E6QPZG1PPQ,204
21
- fabricatio-0.2.0.dev1.dist-info/METADATA,sha256=RIwaKlrpJQplobxDYSljYSlUXwC-Ai2F1SPYzBxGG0A,7054
22
- fabricatio-0.2.0.dev1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
23
- fabricatio-0.2.0.dev1.dist-info/licenses/LICENSE,sha256=do7J7EiCGbq0QPbMAL_FqLYufXpHnCnXBOuqVPwSV8Y,1088
24
- fabricatio-0.2.0.dev1.dist-info/RECORD,,