fred-oss 0.56.0__tar.gz → 0.57.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 (130) hide show
  1. {fred_oss-0.56.0/src/main/fred_oss.egg-info → fred_oss-0.57.0}/PKG-INFO +1 -1
  2. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/router/endpoint.py +5 -2
  3. fred_oss-0.57.0/src/main/fred/version +1 -0
  4. fred_oss-0.57.0/src/main/fred/worker/runner/rest/router/_base.py +22 -0
  5. {fred_oss-0.56.0/src/main/fred/worker/runner/rest/routers → fred_oss-0.57.0/src/main/fred/worker/runner/rest/router}/_runner.py +51 -62
  6. fred_oss-0.57.0/src/main/fred/worker/runner/rest/router/catalog.py +11 -0
  7. {fred_oss-0.56.0 → fred_oss-0.57.0/src/main/fred_oss.egg-info}/PKG-INFO +1 -1
  8. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred_oss.egg-info/SOURCES.txt +4 -8
  9. fred_oss-0.56.0/src/main/fred/version +0 -1
  10. fred_oss-0.56.0/src/main/fred/worker/runner/rest/auth.py +0 -22
  11. fred_oss-0.56.0/src/main/fred/worker/runner/rest/cli_ext.py +0 -32
  12. fred_oss-0.56.0/src/main/fred/worker/runner/rest/routers/catalog.py +0 -18
  13. fred_oss-0.56.0/src/main/fred/worker/runner/rest/routers/interface.py +0 -59
  14. fred_oss-0.56.0/src/main/fred/worker/runner/rest/server.py +0 -85
  15. fred_oss-0.56.0/src/main/fred/worker/runner/rest/settings.py +0 -21
  16. {fred_oss-0.56.0 → fred_oss-0.57.0}/MANIFEST.in +0 -0
  17. {fred_oss-0.56.0 → fred_oss-0.57.0}/NOTICE.txt +0 -0
  18. {fred_oss-0.56.0 → fred_oss-0.57.0}/README.md +0 -0
  19. {fred_oss-0.56.0 → fred_oss-0.57.0}/requirements.txt +0 -0
  20. {fred_oss-0.56.0 → fred_oss-0.57.0}/setup.cfg +0 -0
  21. {fred_oss-0.56.0 → fred_oss-0.57.0}/setup.py +0 -0
  22. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/cli/__init__.py +0 -0
  23. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/cli/__main__.py +0 -0
  24. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/cli/interface.py +0 -0
  25. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/cli/main.py +0 -0
  26. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/__init__.py +0 -0
  27. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/comp/__init__.py +0 -0
  28. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/comp/_keyval.py +0 -0
  29. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/comp/_pubsub.py +0 -0
  30. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/comp/_queue.py +0 -0
  31. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/comp/catalog.py +0 -0
  32. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/comp/interface.py +0 -0
  33. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/__init__.py +0 -0
  34. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/_minio/__init__.py +0 -0
  35. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/_minio/policy/__init__.py +0 -0
  36. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/_minio/policy/builder.py +0 -0
  37. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/_minio/policy/catalog.py +0 -0
  38. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/_minio/policy/loader.py +0 -0
  39. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/_minio/policy/templates/public_ro.json +0 -0
  40. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/_minio/policy/templates/public_rw.json +0 -0
  41. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/_minio/pool.py +0 -0
  42. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/_minio/service.py +0 -0
  43. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/_redis.py +0 -0
  44. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/_stdlib.py +0 -0
  45. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/catalog.py +0 -0
  46. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/interface.py +0 -0
  47. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/dao/service/utils.py +0 -0
  48. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/future/__init__.py +0 -0
  49. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/future/callback/__init__.py +0 -0
  50. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/future/callback/_function.py +0 -0
  51. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/future/callback/catalog.py +0 -0
  52. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/future/callback/interface.py +0 -0
  53. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/future/impl.py +0 -0
  54. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/future/result.py +0 -0
  55. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/future/settings.py +0 -0
  56. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/future/utils.py +0 -0
  57. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/integrations/databricks/__init__.py +0 -0
  58. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/integrations/databricks/cli_ext.py +0 -0
  59. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/integrations/databricks/runtime.py +0 -0
  60. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/integrations/databricks/runtimes/16.4LTS.json +0 -0
  61. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/integrations/databricks/runtimes/__init__.py +0 -0
  62. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/integrations/databricks/runtimes/scanner.py +0 -0
  63. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/integrations/databricks/runtimes/sync.py +0 -0
  64. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/integrations/databricks/wrappers/__init__.py +0 -0
  65. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/integrations/databricks/wrappers/dbutils.py +0 -0
  66. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/integrations/runpod/__init__.py +0 -0
  67. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/integrations/runpod/cli_ext.py +0 -0
  68. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/integrations/runpod/helper.py +0 -0
  69. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/maturity.py +0 -0
  70. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/monad/__init__.py +0 -0
  71. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/monad/_either.py +0 -0
  72. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/monad/catalog.py +0 -0
  73. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/monad/interface.py +0 -0
  74. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/__init__.py +0 -0
  75. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/auth.py +0 -0
  76. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/config.py +0 -0
  77. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/router/__init__.py +0 -0
  78. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/router/catalog/__init__.py +0 -0
  79. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/router/catalog/default/__init__.py +0 -0
  80. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/router/catalog/default/_base.py +0 -0
  81. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/router/catalog/default/_example.py +0 -0
  82. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/router/catalog/default/catalog.py +0 -0
  83. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/router/catalog/interface.py +0 -0
  84. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/router/config.py +0 -0
  85. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/router/interface.py +0 -0
  86. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/server.py +0 -0
  87. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/rest/settings.py +0 -0
  88. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/settings.py +0 -0
  89. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/utils/__init__.py +0 -0
  90. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/utils/dateops.py +0 -0
  91. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/utils/imops.py +0 -0
  92. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/utils/imout/__init__.py +0 -0
  93. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/utils/imout/_filesystem.py +0 -0
  94. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/utils/imout/_minio.py +0 -0
  95. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/utils/imout/_string.py +0 -0
  96. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/utils/imout/catalog.py +0 -0
  97. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/utils/imout/interface.py +0 -0
  98. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/utils/mlops/__init__.py +0 -0
  99. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/utils/mlops/auto.py +0 -0
  100. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/utils/runtime.py +0 -0
  101. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/version.py +0 -0
  102. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/__init__.py +0 -0
  103. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/interface.py +0 -0
  104. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/__init__.py +0 -0
  105. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/backend.py +0 -0
  106. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/client.py +0 -0
  107. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/handler.py +0 -0
  108. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/model/__init__.py +0 -0
  109. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/model/_handler.py +0 -0
  110. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/model/_item.py +0 -0
  111. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/model/_request.py +0 -0
  112. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/model/_runner_spec.py +0 -0
  113. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/model/catalog.py +0 -0
  114. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/model/interface.py +0 -0
  115. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/plugins/__init__.py +0 -0
  116. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/plugins/_local.py +0 -0
  117. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/plugins/_runpod.py +0 -0
  118. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/plugins/catalog.py +0 -0
  119. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/plugins/interface.py +0 -0
  120. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/rest/__init__.py +0 -0
  121. {fred_oss-0.56.0/src/main/fred/worker/runner/rest/routers → fred_oss-0.57.0/src/main/fred/worker/runner/rest/router}/__init__.py +0 -0
  122. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/settings.py +0 -0
  123. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/signal.py +0 -0
  124. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/status.py +0 -0
  125. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/runner/utils.py +0 -0
  126. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred/worker/settings.py +0 -0
  127. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred_oss.egg-info/dependency_links.txt +0 -0
  128. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred_oss.egg-info/entry_points.txt +0 -0
  129. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred_oss.egg-info/requires.txt +0 -0
  130. {fred_oss-0.56.0 → fred_oss-0.57.0}/src/main/fred_oss.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fred-oss
3
- Version: 0.56.0
3
+ Version: 0.57.0
4
4
  Summary: FREDOSS
5
5
  Home-page: https://fred.fahera.mx
6
6
  Author: Fahera Research, Education, and Development
@@ -62,7 +62,7 @@ class RouterEndpointAnnotation(RouterEndpoint):
62
62
  config = RouterEndpointConfig.auto(**kwargs)
63
63
  return lambda function: cls(function=function, configs=config)
64
64
 
65
- def __get__(self, other, other_type):
65
+ def __get__(self, other_instance, other_class) -> RouterEndpoint:
66
66
  # Create a partial function that binds the instance (other) to the method.
67
67
  # This method was originally implemented using the following approaches:
68
68
  # - function = functools.partial(self.function, other)
@@ -87,7 +87,10 @@ class RouterEndpointAnnotation(RouterEndpoint):
87
87
  params.update(await request.json())
88
88
  except Exception:
89
89
  pass
90
- return self.function(other, **params)
90
+ # Since the annotation is usually applied to methods within a class,
91
+ # in most cases the 'other_instance' will be 'None'; therefore using 'other_class'
92
+ # should allow accessing the shared-class level state (e.g., runner_backend).
93
+ return self.function(other_class, **params)
91
94
  return RouterEndpoint(
92
95
  function=closure,
93
96
  configs=self.configs
@@ -0,0 +1 @@
1
+ 0.57.0
@@ -0,0 +1,22 @@
1
+ from dataclasses import dataclass
2
+
3
+ from fred.rest.router.interface import RouterInterfaceMixin
4
+ from fred.rest.router.endpoint import RouterEndpointAnnotation
5
+
6
+ @dataclass(frozen=True, slots=True)
7
+ class RouterBaseMixin(RouterInterfaceMixin):
8
+
9
+ @RouterEndpointAnnotation.set(
10
+ path="/",
11
+ methods=["GET"],
12
+ summary="Base endpoint",
13
+ description="A simple base endpoint to check service availability."
14
+ )
15
+ def base(self, include_telemetry: bool = False, **kwargs) -> dict:
16
+ if include_telemetry:
17
+ from fred.utils.runtime import RuntimeProfilingSnapshot
18
+ kwargs["telemetry"] = RuntimeProfilingSnapshot.auto().to_dict()
19
+ return {
20
+ "ok": True,
21
+ **kwargs
22
+ }
@@ -1,17 +1,24 @@
1
- from dataclasses import dataclass
2
1
  from typing import Optional
3
2
 
4
3
  from fred.future import Future
5
4
  from fred.settings import logger_manager
6
5
  from fred.utils.dateops import datetime_utcnow
7
- from fred.worker.runner.rest.routers.interface import RouterInterface
6
+ from fred.rest.router.interface import RouterInterfaceMixin
7
+ from fred.rest.router.endpoint import RouterEndpointAnnotation
8
8
 
9
9
  logger = logger_manager.get_logger(name=__name__)
10
10
 
11
11
 
12
- class RunnerRouterMethods:
12
+ class RunnerRouterMixin(RouterInterfaceMixin):
13
13
 
14
- def handler_exists(self, classname: str, classpath: str) -> dict:
14
+ @RouterEndpointAnnotation.set(
15
+ path="/handler_exists",
16
+ methods=["GET"],
17
+ tags=["Runner"],
18
+ summary="Check if a handler class exists and is a RunnerHandler.",
19
+ response_description="Details about the handler class.",
20
+ )
21
+ def handler_exists(self, classname: str, classpath: str, **kwargs) -> dict:
15
22
  from fred.worker.runner.handler import RunnerHandler
16
23
  from fred.worker.interface import HandlerInterface
17
24
 
@@ -35,8 +42,15 @@ class RunnerRouterMethods:
35
42
  result_payload["metadata"]["error"] = str(e)
36
43
  return result_payload
37
44
 
38
- def qlen(self, queue_slug: str) -> dict:
39
45
 
46
+ @RouterEndpointAnnotation.set(
47
+ path="/qlen/{queue_slug}",
48
+ methods=["GET"],
49
+ tags=["Runner"],
50
+ summary="Get the length of the request and response queues for a given queue slug.",
51
+ response_description="The lengths of the request and response queues.",
52
+ )
53
+ def qlen(self, queue_slug: str, **kwargs) -> dict:
40
54
  snapshot_at = datetime_utcnow().isoformat()
41
55
  req_queue = self.runner_backend.queue(f"req:{queue_slug}")
42
56
  res_queue = self.runner_backend.queue(f"res:{queue_slug}")
@@ -49,34 +63,48 @@ class RunnerRouterMethods:
49
63
  "res": res_queue.size(),
50
64
  }
51
65
 
52
- def runner_start(self, payload: dict) -> dict:
66
+ @RouterEndpointAnnotation.set(
67
+ path="/start",
68
+ methods=["POST"],
69
+ tags=["Runner"],
70
+ summary="Start a runner using the specified plugin.",
71
+ response_description="The ID of the started runner.",
72
+ )
73
+ def runner_start(self, **kwargs) -> dict:
53
74
  from fred.worker.runner.model.catalog import RunnerModelCatalog
54
75
  from fred.worker.runner.plugins.catalog import PluginCatalog
55
76
  # Determine which plugin to use; default to LOCAL if not specified
56
- plugin_name: str = payload.pop("plugin", "LOCAL")
57
- wait_for_exec: bool = payload.pop("wait_for_exec", False)
77
+ plugin_name: str = kwargs.pop("plugin", "LOCAL")
78
+ wait_for_exec: bool = kwargs.pop("wait_for_exec", False)
58
79
  # Create the RunnerSpec from the provided payload
59
80
  # TODO: Instead on depending on parsing a dict... Can we implement a base-model to facilitate fast-api validation?
60
- runner_spec = RunnerModelCatalog.RUNNER_SPEC.value.from_payload(payload=payload)
81
+ runner_spec = RunnerModelCatalog.RUNNER_SPEC.value.from_payload(payload=kwargs)
61
82
  # Instantiate the plugin and execute the runner
62
83
  plugin = PluginCatalog[plugin_name.upper()]()
63
- output = plugin.execute(runner_spec, wait_for_exec=wait_for_exec, **payload)
84
+ output = plugin.execute(runner_spec, wait_for_exec=wait_for_exec, **kwargs)
64
85
  return {
65
86
  "runner_id": output.runner_id,
66
87
  "future_id": output.future_exec.future_id,
67
88
  "queue_slug": runner_spec.queue_slug,
68
89
  }
69
-
70
- def runner_execute(self, payload: dict) -> dict:
90
+
91
+ @RouterEndpointAnnotation.set(
92
+ path="/execute",
93
+ methods=["POST"],
94
+ tags=["Runner"],
95
+ summary="Execute a task by dispatching a request to the specified queue.",
96
+ response_description="Details about the dispatched request.",
97
+ )
98
+ def runner_execute(self, **kwargs) -> dict:
71
99
  from fred.worker.runner.model.catalog import RunnerModelCatalog
72
100
 
73
- request_id = payload.pop("request_id", None)
74
- queue_slug = payload.pop("queue_slug", None) or (
101
+ request_id = kwargs.pop("request_id", None)
102
+ queue_slug = kwargs.pop("queue_slug", None) or (
75
103
  logger.error("No 'queue_slug' value provided; defaulting to 'demo'.")
76
104
  or "demo"
77
105
  )
78
106
 
79
- item = RunnerModelCatalog.ITEM.value.uuid(payload=payload, uuid_hash=False)
107
+ item = RunnerModelCatalog.ITEM.value.uuid(payload=kwargs, uuid_hash=False)
80
108
  request = item.as_request(use_hash=False, request_id=request_id)
81
109
  request.dispatch(
82
110
  request_queue=self.runner_backend.queue(f"req:{queue_slug}")
@@ -88,7 +116,14 @@ class RunnerRouterMethods:
88
116
  "dispatched_at": datetime_utcnow().isoformat(),
89
117
  }
90
118
 
91
- def runner_output(self, request_id: str, nonblocking: bool = False, timeout: Optional[float] = None) -> dict:
119
+ @RouterEndpointAnnotation.set(
120
+ path="/output/{request_id}",
121
+ methods=["GET"],
122
+ tags=["Runner"],
123
+ summary="Fetch the output of a previously dispatched request.",
124
+ response_description="The output of the request.",
125
+ )
126
+ def runner_output(self, request_id: str, nonblocking: bool = False, timeout: Optional[float] = None, **kwargs) -> dict:
92
127
 
93
128
  output_requested_at = datetime_utcnow().isoformat()
94
129
  # Subscribe to the future result using the request_id
@@ -102,49 +137,3 @@ class RunnerRouterMethods:
102
137
  "output_delivered_at": datetime_utcnow().isoformat(),
103
138
  "output": future.wait_and_resolve(timeout=timeout),
104
139
  }
105
-
106
-
107
- @dataclass(frozen=True, slots=False)
108
- class RunnerRouter(RouterInterface.with_backend(), RunnerRouterMethods):
109
-
110
- def __post_init__(self):
111
- self.router.add_api_route(
112
- "/handler_exists",
113
- self.handler_exists,
114
- methods=["GET"],
115
- tags=["Runner"],
116
- summary="Check if a handler class exists and is a RunnerHandler.",
117
- response_description="Details about the handler class.",
118
- )
119
- self.router.add_api_route(
120
- "/qlen/{queue_slug}",
121
- self.qlen,
122
- methods=["GET"],
123
- tags=["Runner"],
124
- summary="Get the length of the request and response queues for a given queue slug.",
125
- response_description="The lengths of the request and response queues.",
126
- )
127
- self.router.add_api_route(
128
- "/start",
129
- self.runner_start,
130
- methods=["POST"],
131
- tags=["Runner"],
132
- summary="Start a runner using the specified plugin.",
133
- response_description="The ID of the started runner.",
134
- )
135
- self.router.add_api_route(
136
- "/execute",
137
- self.runner_execute,
138
- methods=["POST"],
139
- tags=["Runner"],
140
- summary="Execute a task by dispatching a request to the specified queue.",
141
- response_description="Details about the dispatched request.",
142
- )
143
- self.router.add_api_route(
144
- "/output/{request_id}",
145
- self.runner_output,
146
- methods=["GET"],
147
- tags=["Runner"],
148
- summary="Fetch the output of a previously dispatched request.",
149
- response_description="The output of the request.",
150
- )
@@ -0,0 +1,11 @@
1
+ import enum
2
+
3
+ from fred.rest.router.config import RouterConfig
4
+ from fred.rest.router.catalog.interface import RouterCatalogInterface
5
+ from fred.worker.runner.rest.router._runner import RunnerRouterMixin
6
+ from fred.worker.runner.rest.router._base import RouterBaseMixin
7
+
8
+
9
+ class RouterCatalog(RouterCatalogInterface, enum.Enum):
10
+ BASE = RouterConfig.auto(prefix="")(apply=RouterBaseMixin)
11
+ RUNNER = RouterConfig.auto(prefix="/runner", tags=["Runner"])(apply=RunnerRouterMixin)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fred-oss
3
- Version: 0.56.0
3
+ Version: 0.57.0
4
4
  Summary: FREDOSS
5
5
  Home-page: https://fred.fahera.mx
6
6
  Author: Fahera Research, Education, and Development
@@ -109,14 +109,10 @@ src/main/fred/worker/runner/plugins/_runpod.py
109
109
  src/main/fred/worker/runner/plugins/catalog.py
110
110
  src/main/fred/worker/runner/plugins/interface.py
111
111
  src/main/fred/worker/runner/rest/__init__.py
112
- src/main/fred/worker/runner/rest/auth.py
113
- src/main/fred/worker/runner/rest/cli_ext.py
114
- src/main/fred/worker/runner/rest/server.py
115
- src/main/fred/worker/runner/rest/settings.py
116
- src/main/fred/worker/runner/rest/routers/__init__.py
117
- src/main/fred/worker/runner/rest/routers/_runner.py
118
- src/main/fred/worker/runner/rest/routers/catalog.py
119
- src/main/fred/worker/runner/rest/routers/interface.py
112
+ src/main/fred/worker/runner/rest/router/__init__.py
113
+ src/main/fred/worker/runner/rest/router/_base.py
114
+ src/main/fred/worker/runner/rest/router/_runner.py
115
+ src/main/fred/worker/runner/rest/router/catalog.py
120
116
  src/main/fred_oss.egg-info/PKG-INFO
121
117
  src/main/fred_oss.egg-info/SOURCES.txt
122
118
  src/main/fred_oss.egg-info/dependency_links.txt
@@ -1 +0,0 @@
1
- 0.56.0
@@ -1,22 +0,0 @@
1
- from fastapi import Security, HTTPException, status
2
- from fastapi.security import APIKeyHeader
3
-
4
- from fred.worker.runner.rest.settings import FRD_RESTAPI_TOKEN
5
-
6
- async def verify_key(
7
- api_key_header: str = Security(
8
- APIKeyHeader(
9
- name="X-API-Key",
10
- auto_error=False
11
- )
12
- ),
13
- ):
14
- """
15
- Verify the provided API key against the expected token.
16
- Raises an HTTPException if the key is invalid or missing.
17
- """
18
- if api_key_header != FRD_RESTAPI_TOKEN:
19
- raise HTTPException(
20
- status_code=status.HTTP_401_UNAUTHORIZED,
21
- detail="Invalid or missing API Key",
22
- )
@@ -1,32 +0,0 @@
1
- from typing import Optional
2
-
3
- from fred.cli.interface import IntegrationExtCLI
4
- from fred.settings import logger_manager
5
-
6
-
7
- logger = logger_manager.get_logger(name=__name__)
8
-
9
-
10
- class RunnerServerExt(IntegrationExtCLI):
11
-
12
- def start(
13
- self,
14
- include_routers: Optional[list[str]] = None,
15
- exclude_routers: Optional[list[str]] = None,
16
- fast_api_configs: Optional[dict] = None,
17
- server_configs: Optional[dict] = None,
18
- ):
19
- from fred.worker.runner.rest.server import RunnerServer
20
-
21
- include_routers = include_routers or []
22
- exclude_routers = exclude_routers or []
23
- fast_api_configs = fast_api_configs or {}
24
- server_configs = server_configs or {}
25
-
26
- logger.info("Starting REST server...")
27
- server = RunnerServer.auto(
28
- include_routers=include_routers,
29
- exclude_routers=exclude_routers,
30
- **fast_api_configs,
31
- )
32
- server.start(**server_configs)
@@ -1,18 +0,0 @@
1
- import enum
2
-
3
- from fred.worker.runner.rest.routers.interface import RouterInterface
4
- from fred.worker.runner.rest.routers._runner import RunnerRouter
5
-
6
-
7
- class RouterCatalog(enum.Enum):
8
- EXAMPLE = RouterInterface.auto() # Default example router directly from the base interface
9
- RUNNER = RunnerRouter.auto(
10
- prefix="/runner",
11
- tags=["Runner"],
12
- )
13
-
14
- def get_router_instance(self) -> RouterInterface:
15
- return self.value.router
16
-
17
- def get_router_configs(self) -> dict:
18
- return self.value.router_configs
@@ -1,59 +0,0 @@
1
- from dataclasses import dataclass
2
- from typing import Optional
3
-
4
- from fred.worker.runner.backend import RunnerBackend
5
- from fred.worker.runner.settings import FRD_RUNNER_BACKEND
6
-
7
- from fastapi import APIRouter
8
-
9
-
10
- class RouterInterfaceBackendMixin:
11
- """Base class for router interfaces that require a backend service."""
12
- runner_backend: RunnerBackend
13
-
14
- @classmethod
15
- def with_backend(cls, service_name: Optional[str] = None, **kwargs) -> type["RouterInterfaceBackendMixin"]:
16
- # Avoid re-initializing if already set
17
- if getattr(cls, "runner_backend", None):
18
- return cls
19
- # Initialize the backend once and assign to the class attribute
20
- cls.runner_backend = RunnerBackend.auto(
21
- service_name=service_name or FRD_RUNNER_BACKEND,
22
- **kwargs,
23
- )
24
- return cls
25
-
26
-
27
- @dataclass(frozen=True, slots=False)
28
- class RouterInterface(RouterInterfaceBackendMixin):
29
- router: APIRouter
30
- router_configs: dict
31
-
32
- @classmethod
33
- def auto(
34
- cls,
35
- router: Optional[APIRouter] = None,
36
- **kwargs,
37
- ) -> "RouterInterface":
38
- return cls(
39
- router=router or APIRouter(),
40
- router_configs=kwargs,
41
- )
42
-
43
- def __post_init__(self):
44
- self.router.add_api_route(
45
- "/ping",
46
- self.ping,
47
- methods=["GET"],
48
- tags=["Health"],
49
- summary="Ping the server to check if it's alive.",
50
- response_description="A simple pong response.",
51
- )
52
-
53
- def ping(self, pong: Optional[str] = None) -> dict:
54
- from fred.utils.dateops import datetime_utcnow
55
-
56
- return {
57
- "ping_time": datetime_utcnow().isoformat(),
58
- "ping_response": pong or "pong",
59
- }
@@ -1,85 +0,0 @@
1
- from dataclasses import dataclass
2
-
3
- from fastapi import FastAPI, Depends
4
-
5
- from fred.settings import logger_manager, get_environ_variable
6
- from fred.worker.runner.rest.settings import (
7
- FRD_RESTAPI_HOST,
8
- FRD_RESTAPI_PORT,
9
- )
10
- from fred.worker.runner.rest.routers.catalog import RouterCatalog
11
- from fred.worker.runner.rest.auth import verify_key
12
-
13
- logger = logger_manager.get_logger(name=__name__)
14
-
15
-
16
- @dataclass(frozen=True, slots=True)
17
- class RunnerServer:
18
- app: FastAPI
19
- include_routers: list[str]
20
- exclude_routers: list[str]
21
-
22
- @classmethod
23
- def auto(cls, **kwargs) -> "RunnerServer":
24
- # Include routers by checking on keyword argument or environment variable
25
- include_routers = kwargs.pop("include_routers", None) or get_environ_variable(
26
- "FRD_RUNNER_API_INCLUDE_ROUTERS",
27
- default=""
28
- )
29
- if isinstance(include_routers, str):
30
- include_routers = [
31
- name.upper()
32
- for router in include_routers.split(";")
33
- if (name := router.strip())
34
- ]
35
- # Exclude routers by checking on keyword argument or environment variable
36
- exclude_routers = kwargs.pop("exclude_routers", None) or get_environ_variable(
37
- "FRD_RUNNER_API_EXCLUDE_ROUTERS",
38
- default=""
39
- )
40
- if isinstance(exclude_routers, str):
41
- exclude_routers = [
42
- name.upper()
43
- for router in exclude_routers.split(";")
44
- if (name := router.strip())
45
- ]
46
- # Create FastAPI instance
47
- kwargs["dependencies"] = kwargs.get("dependencies", []) + [
48
- Depends(verify_key),
49
- ]
50
- app_instance = FastAPI(**kwargs)
51
- return cls(
52
- app=app_instance,
53
- include_routers=include_routers,
54
- exclude_routers=exclude_routers,
55
- )
56
-
57
- def __post_init__(self):
58
- logger.info("Attempting to register routers...")
59
- logger.info("Included routers candidates: %s", self.include_routers or "ALL")
60
- logger.info("Excluded routers candidates: %s", self.exclude_routers or "NONE")
61
- for router in RouterCatalog:
62
- name = router.name.upper()
63
- if self.include_routers and name not in self.include_routers:
64
- logger.info(f"Skipping router '{name}' as it's not in the include list.")
65
- continue
66
- if self.exclude_routers and name in self.exclude_routers:
67
- logger.info(f"Skipping router '{name}' as it's in the exclude list.")
68
- continue
69
- logger.info(f"Registering router '{name}'.")
70
- self.app.include_router(
71
- router.get_router_instance(),
72
- **router.get_router_configs(),
73
- )
74
-
75
- def start(self, **kwargs):
76
- import uvicorn
77
-
78
- server_kwargs = {
79
- "host": kwargs.pop("host", FRD_RESTAPI_HOST),
80
- "port": int(kwargs.pop("port", FRD_RESTAPI_PORT)),
81
- "log_level": "info",
82
- **kwargs,
83
- }
84
-
85
- uvicorn.run(self.app, **server_kwargs)
@@ -1,21 +0,0 @@
1
- from fred.settings import get_environ_variable, logger_manager
2
-
3
- logger = logger_manager.get_logger(name=__name__)
4
-
5
-
6
- FRD_RESTAPI_HOST = get_environ_variable(
7
- "FRD_RESTAPI_HOST",
8
- default="0.0.0.0"
9
- )
10
- FRD_RESTAPI_PORT = int(get_environ_variable(
11
- "FRD_RESTAPI_PORT",
12
- default=8000
13
- ))
14
-
15
- FRD_RESTAPI_TOKEN = get_environ_variable(
16
- "FRD_RESTAPI_TOKEN",
17
- default=None
18
- )
19
- if not FRD_RESTAPI_TOKEN:
20
- logger.warning("FRD_RESTAPI_TOKEN not found in environment; using default token 'changeme'.")
21
- FRD_RESTAPI_TOKEN = "changeme"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes