nebu 0.1.52__tar.gz → 0.1.55__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.
- {nebu-0.1.52/src/nebu.egg-info → nebu-0.1.55}/PKG-INFO +1 -1
- {nebu-0.1.52 → nebu-0.1.55}/pyproject.toml +1 -1
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/config.py +13 -6
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/processors/decorate.py +93 -30
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/processors/processor.py +6 -4
- {nebu-0.1.52 → nebu-0.1.55/src/nebu.egg-info}/PKG-INFO +1 -1
- {nebu-0.1.52 → nebu-0.1.55}/LICENSE +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/README.md +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/setup.cfg +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/__init__.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/auth.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/builders/builder.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/builders/models.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/cache.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/containers/container.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/containers/decorator.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/containers/models.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/containers/server.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/data.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/meta.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/processors/consumer.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/processors/default.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/processors/models.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/processors/remote.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/redis/models.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu/services/service.py +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu.egg-info/SOURCES.txt +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu.egg-info/dependency_links.txt +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu.egg-info/requires.txt +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/src/nebu.egg-info/top_level.txt +0 -0
- {nebu-0.1.52 → nebu-0.1.55}/tests/test_containers.py +0 -0
@@ -52,12 +52,17 @@ class GlobalConfig:
|
|
52
52
|
config = cls() # default
|
53
53
|
|
54
54
|
# Collect environment variables (no fallback defaults here)
|
55
|
-
env_api_key =
|
56
|
-
"
|
55
|
+
env_api_key = (
|
56
|
+
os.environ.get("NEBU_API_KEY")
|
57
|
+
or os.environ.get("AGENTSEA_API_KEY")
|
58
|
+
or os.environ.get("ORIGN_API_KEY")
|
57
59
|
)
|
58
|
-
env_server = os.environ.get("NEBU_SERVER")
|
59
|
-
env_auth_server =
|
60
|
-
"
|
60
|
+
env_server = os.environ.get("NEBU_SERVER")
|
61
|
+
env_auth_server = (
|
62
|
+
os.environ.get("NEBU_AUTH_SERVER")
|
63
|
+
or os.environ.get("AGENTSEA_AUTH_SERVER")
|
64
|
+
or os.environ.get("ORIGN_AUTH_SERVER")
|
65
|
+
or os.environ.get("AGENTSEA_AUTH_URL")
|
61
66
|
)
|
62
67
|
|
63
68
|
# Only proceed if all three environment variables are present
|
@@ -158,7 +163,9 @@ class ContainerConfig:
|
|
158
163
|
Load configuration from environment variables.
|
159
164
|
"""
|
160
165
|
return cls(
|
161
|
-
api_key=os.environ.get("NEBU_API_KEY")
|
166
|
+
api_key=os.environ.get("NEBU_API_KEY")
|
167
|
+
or os.environ.get("AGENTSEA_API_KEY")
|
168
|
+
or os.environ.get("ORIGN_API_KEY"),
|
162
169
|
server=os.environ.get("NEBU_SERVER"),
|
163
170
|
namespace=os.environ.get("NEBU_NAMESPACE"),
|
164
171
|
name=os.environ.get("NEBU_NAME"),
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import ast # For parsing notebook code
|
2
2
|
import inspect
|
3
3
|
import os
|
4
|
+
import re # Added import
|
4
5
|
import textwrap
|
5
6
|
from typing import (
|
6
7
|
Any,
|
@@ -75,9 +76,10 @@ def is_jupyter_notebook():
|
|
75
76
|
|
76
77
|
if importlib.util.find_spec("IPython") is None:
|
77
78
|
return False
|
78
|
-
|
79
|
+
# Fix: Import get_ipython directly
|
80
|
+
from IPython.core.getipython import get_ipython # Now safe to import
|
79
81
|
|
80
|
-
ip =
|
82
|
+
ip = get_ipython() # Use the imported function
|
81
83
|
if ip is None: # type: ignore
|
82
84
|
# print("[DEBUG Helper] is_jupyter_notebook: No IPython instance found.")
|
83
85
|
return False
|
@@ -102,9 +104,10 @@ def get_notebook_executed_code():
|
|
102
104
|
"""
|
103
105
|
print("[DEBUG Helper] Attempting to get notebook execution history...")
|
104
106
|
try:
|
105
|
-
|
107
|
+
# Fix: Import get_ipython directly
|
108
|
+
from IPython.core.getipython import get_ipython
|
106
109
|
|
107
|
-
ip =
|
110
|
+
ip = get_ipython() # Use the imported function
|
108
111
|
if ip is None or not hasattr(ip, "history_manager"):
|
109
112
|
print(
|
110
113
|
"[DEBUG Helper] get_notebook_executed_code: No IPython instance or history_manager."
|
@@ -187,12 +190,14 @@ def extract_definition_source_from_string(
|
|
187
190
|
start_lineno = getattr(node, "lineno", 1) - 1
|
188
191
|
end_lineno = getattr(node, "end_lineno", start_lineno + 1)
|
189
192
|
|
190
|
-
if hasattr(node, "decorator_list") and node.decorator_list:
|
193
|
+
if hasattr(node, "decorator_list") and node.decorator_list: # type: ignore
|
191
194
|
# Ensure it's a node type that *can* have decorators
|
192
195
|
# FunctionDef and ClassDef have decorator_list
|
193
196
|
first_decorator_start_line = (
|
194
197
|
getattr(
|
195
|
-
node.decorator_list[0],
|
198
|
+
node.decorator_list[0], # type: ignore
|
199
|
+
"lineno",
|
200
|
+
start_lineno + 1,
|
196
201
|
)
|
197
202
|
- 1
|
198
203
|
) # type: ignore
|
@@ -391,13 +396,13 @@ def processor(
|
|
391
396
|
):
|
392
397
|
def decorator(
|
393
398
|
func: Callable[[Any], Any],
|
394
|
-
) -> Processor
|
399
|
+
) -> Processor:
|
395
400
|
# --- Prevent Recursion Guard ---
|
396
401
|
if os.environ.get(_NEBU_INSIDE_CONSUMER_ENV_VAR) == "1":
|
397
402
|
print(
|
398
403
|
f"[DEBUG Decorator] Guard triggered for '{func.__name__}'. Returning original function."
|
399
404
|
)
|
400
|
-
return func
|
405
|
+
return func # type: ignore
|
401
406
|
# --- End Guard ---
|
402
407
|
|
403
408
|
print(
|
@@ -599,7 +604,7 @@ def processor(
|
|
599
604
|
included_sources[obj] = obj_source
|
600
605
|
# Decide how to pass included source - keep using Env Vars for now
|
601
606
|
env_key_base = f"INCLUDED_OBJECT_{i}"
|
602
|
-
if isinstance(obj_source, str):
|
607
|
+
if isinstance(obj_source, str): # type: ignore[arg-type]
|
603
608
|
all_env.append(
|
604
609
|
V1EnvVar(key=f"{env_key_base}_SOURCE", value=obj_source)
|
605
610
|
)
|
@@ -609,7 +614,7 @@ def processor(
|
|
609
614
|
# Ensure obj_source is indeed a tuple before unpacking
|
610
615
|
if len(obj_source) == 2:
|
611
616
|
# Now safe to unpack
|
612
|
-
origin_src, arg_srcs = obj_source
|
617
|
+
origin_src, arg_srcs = obj_source # type: ignore[misc] # Suppress persistent tuple unpacking error
|
613
618
|
# type: ignore[misc] # Suppress persistent tuple unpacking error
|
614
619
|
if origin_src and isinstance(origin_src, str):
|
615
620
|
all_env.append(
|
@@ -708,6 +713,7 @@ def processor(
|
|
708
713
|
print(f"[DEBUG Decorator] get_origin result: {origin}, get_args result: {args}")
|
709
714
|
is_stream_message = False
|
710
715
|
content_type = None
|
716
|
+
content_type_name_from_regex = None # Store regex result here
|
711
717
|
|
712
718
|
# Use Message class directly for comparison
|
713
719
|
message_cls = Message # Get the class object
|
@@ -727,18 +733,63 @@ def processor(
|
|
727
733
|
)
|
728
734
|
else:
|
729
735
|
print(
|
730
|
-
"[DEBUG Decorator] Message detected, but no generic arguments found via get_args."
|
736
|
+
"[DEBUG Decorator] Message detected, but no generic arguments found via get_args. Attempting regex fallback on string repr."
|
731
737
|
)
|
738
|
+
# --- Regex Fallback Start ---
|
739
|
+
match = re.search(r"Message\[([\w\.]+)\]", param_type_str_repr)
|
740
|
+
if match:
|
741
|
+
content_type_name_from_regex = match.group(1)
|
742
|
+
print(
|
743
|
+
f"[DEBUG Decorator] Extracted content type name via regex: {content_type_name_from_regex}"
|
744
|
+
)
|
745
|
+
else:
|
746
|
+
print(
|
747
|
+
"[DEBUG Decorator] Regex fallback failed to extract content type name."
|
748
|
+
)
|
749
|
+
# --- Regex Fallback End ---
|
750
|
+
# Check 2a: Regex fallback if get_origin failed but string matches pattern
|
751
|
+
elif origin is None and param_type is not None:
|
752
|
+
print(
|
753
|
+
"[DEBUG Decorator] get_origin failed. Attempting regex fallback on string representation."
|
754
|
+
)
|
755
|
+
match = re.search(r"Message\[([\w\.]+)\]", param_type_str_repr)
|
756
|
+
if match:
|
757
|
+
print(
|
758
|
+
"[DEBUG Decorator] Regex fallback successful after get_origin failed."
|
759
|
+
)
|
760
|
+
is_stream_message = True
|
761
|
+
content_type_name_from_regex = match.group(1)
|
762
|
+
# We don't have the actual content_type object here, only the name
|
763
|
+
content_type = None
|
764
|
+
print(
|
765
|
+
f"[DEBUG Decorator] Extracted content type name via regex: {content_type_name_from_regex}"
|
766
|
+
)
|
767
|
+
else:
|
768
|
+
print(
|
769
|
+
"[DEBUG Decorator] Regex fallback also failed. Treating as non-Message type."
|
770
|
+
)
|
771
|
+
is_stream_message = False
|
772
|
+
content_type = None
|
732
773
|
# Check 2: Direct type check (Handles cases where get_origin might fail but type is correct)
|
733
774
|
elif isinstance(param_type, type) and param_type is message_cls:
|
734
|
-
|
775
|
+
# This case likely won't have generic args accessible easily if get_origin failed
|
776
|
+
print(
|
777
|
+
"[DEBUG Decorator] Input type identified as direct Message type. Attempting regex fallback."
|
778
|
+
)
|
735
779
|
is_stream_message = True
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
780
|
+
# --- Regex Fallback Start ---
|
781
|
+
match = re.search(r"Message\[([\w\.]+)\]", param_type_str_repr)
|
782
|
+
if match:
|
783
|
+
content_type_name_from_regex = match.group(1)
|
784
|
+
print(
|
785
|
+
f"[DEBUG Decorator] Extracted content type name via regex: {content_type_name_from_regex}"
|
786
|
+
)
|
787
|
+
else:
|
788
|
+
print(
|
789
|
+
"[DEBUG Decorator] Regex fallback failed to extract content type name."
|
790
|
+
)
|
791
|
+
# --- Regex Fallback End ---
|
792
|
+
# Check 3: Removed old placeholder elif branch
|
742
793
|
|
743
794
|
else: # Handle cases where param_type might be None or origin is something else
|
744
795
|
print(
|
@@ -929,19 +980,31 @@ def processor(
|
|
929
980
|
|
930
981
|
all_env.append(V1EnvVar(key="RETURN_TYPE_STR", value=return_type_str_repr))
|
931
982
|
all_env.append(V1EnvVar(key="IS_STREAM_MESSAGE", value=str(is_stream_message)))
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
983
|
+
|
984
|
+
# Determine and set CONTENT_TYPE_NAME using object or regex fallback
|
985
|
+
content_type_name_to_set = None
|
986
|
+
if content_type and isinstance(content_type, type):
|
987
|
+
content_type_name_to_set = content_type.__name__
|
988
|
+
print(
|
989
|
+
f"[DEBUG Decorator] Using content type name from resolved type object: {content_type_name_to_set}"
|
990
|
+
)
|
991
|
+
elif content_type_name_from_regex:
|
992
|
+
content_type_name_to_set = content_type_name_from_regex
|
993
|
+
print(
|
994
|
+
f"[DEBUG Decorator] Using content type name from regex fallback: {content_type_name_to_set}"
|
995
|
+
)
|
996
|
+
else:
|
997
|
+
# Only warn if it was supposed to be a Message type
|
998
|
+
if is_stream_message:
|
942
999
|
print(
|
943
|
-
f"Warning:
|
1000
|
+
f"Warning: Could not determine CONTENT_TYPE_NAME for Message parameter {param_name} ({param_type_str_repr}). Consumer might use raw content."
|
944
1001
|
)
|
1002
|
+
|
1003
|
+
if content_type_name_to_set:
|
1004
|
+
all_env.append(
|
1005
|
+
V1EnvVar(key="CONTENT_TYPE_NAME", value=content_type_name_to_set)
|
1006
|
+
)
|
1007
|
+
|
945
1008
|
# Use the calculated module_path for MODULE_NAME
|
946
1009
|
all_env.append(
|
947
1010
|
V1EnvVar(
|
@@ -1083,7 +1146,7 @@ def processor(
|
|
1083
1146
|
# setattr(processor_instance, 'original_func', func) # Use setattr if not in model
|
1084
1147
|
try:
|
1085
1148
|
# This will fail if Processor hasn't been updated to include this field
|
1086
|
-
processor_instance.original_func = func
|
1149
|
+
processor_instance.original_func = func # type: ignore
|
1087
1150
|
except AttributeError:
|
1088
1151
|
print(
|
1089
1152
|
"Warning: Could not assign original_func to Processor instance. Update Processor model or remove assignment."
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import json
|
2
2
|
import threading
|
3
|
-
from typing import Any, Dict, List, Optional
|
3
|
+
from typing import Any, Dict, Generic, List, Optional, TypeVar
|
4
4
|
|
5
5
|
import requests
|
6
6
|
from pydantic import BaseModel
|
@@ -19,6 +19,8 @@ from nebu.processors.models import (
|
|
19
19
|
V1UpdateProcessor,
|
20
20
|
)
|
21
21
|
|
22
|
+
InputType = TypeVar("InputType", bound=BaseModel)
|
23
|
+
|
22
24
|
|
23
25
|
def _fetch_and_print_logs(log_url: str, api_key: str, processor_name: str):
|
24
26
|
"""Helper function to fetch logs in a separate thread."""
|
@@ -78,7 +80,7 @@ def _fetch_and_print_logs(log_url: str, api_key: str, processor_name: str):
|
|
78
80
|
)
|
79
81
|
|
80
82
|
|
81
|
-
class Processor:
|
83
|
+
class Processor(Generic[InputType]):
|
82
84
|
"""
|
83
85
|
A class for managing Processor instances.
|
84
86
|
"""
|
@@ -203,14 +205,14 @@ class Processor:
|
|
203
205
|
patch_response.raise_for_status()
|
204
206
|
print(f"Updated Processor {self.processor.metadata.name}")
|
205
207
|
|
206
|
-
def __call__(self, data:
|
208
|
+
def __call__(self, data: InputType, wait: bool = False) -> Dict[str, Any]:
|
207
209
|
"""
|
208
210
|
Allows the Processor instance to be called like a function, sending data.
|
209
211
|
"""
|
210
212
|
return self.send(data=data, wait=wait)
|
211
213
|
|
212
214
|
def send(
|
213
|
-
self, data:
|
215
|
+
self, data: InputType, wait: bool = False, logs: bool = False
|
214
216
|
) -> Dict[str, Any]:
|
215
217
|
"""
|
216
218
|
Send data to the processor and optionally stream logs in the background.
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|