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.
Files changed (31) hide show
  1. {nebu-0.1.52/src/nebu.egg-info → nebu-0.1.55}/PKG-INFO +1 -1
  2. {nebu-0.1.52 → nebu-0.1.55}/pyproject.toml +1 -1
  3. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/config.py +13 -6
  4. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/processors/decorate.py +93 -30
  5. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/processors/processor.py +6 -4
  6. {nebu-0.1.52 → nebu-0.1.55/src/nebu.egg-info}/PKG-INFO +1 -1
  7. {nebu-0.1.52 → nebu-0.1.55}/LICENSE +0 -0
  8. {nebu-0.1.52 → nebu-0.1.55}/README.md +0 -0
  9. {nebu-0.1.52 → nebu-0.1.55}/setup.cfg +0 -0
  10. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/__init__.py +0 -0
  11. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/auth.py +0 -0
  12. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/builders/builder.py +0 -0
  13. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/builders/models.py +0 -0
  14. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/cache.py +0 -0
  15. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/containers/container.py +0 -0
  16. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/containers/decorator.py +0 -0
  17. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/containers/models.py +0 -0
  18. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/containers/server.py +0 -0
  19. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/data.py +0 -0
  20. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/meta.py +0 -0
  21. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/processors/consumer.py +0 -0
  22. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/processors/default.py +0 -0
  23. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/processors/models.py +0 -0
  24. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/processors/remote.py +0 -0
  25. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/redis/models.py +0 -0
  26. {nebu-0.1.52 → nebu-0.1.55}/src/nebu/services/service.py +0 -0
  27. {nebu-0.1.52 → nebu-0.1.55}/src/nebu.egg-info/SOURCES.txt +0 -0
  28. {nebu-0.1.52 → nebu-0.1.55}/src/nebu.egg-info/dependency_links.txt +0 -0
  29. {nebu-0.1.52 → nebu-0.1.55}/src/nebu.egg-info/requires.txt +0 -0
  30. {nebu-0.1.52 → nebu-0.1.55}/src/nebu.egg-info/top_level.txt +0 -0
  31. {nebu-0.1.52 → nebu-0.1.55}/tests/test_containers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nebu
3
- Version: 0.1.52
3
+ Version: 0.1.55
4
4
  Summary: A globally distributed container runtime
5
5
  Requires-Python: >=3.10.14
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nebu"
3
- version = "0.1.52"
3
+ version = "0.1.55"
4
4
  description = "A globally distributed container runtime"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10.14"
@@ -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 = os.environ.get("NEBU_API_KEY") or os.environ.get(
56
- "AGENTSEA_API_KEY"
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") or os.environ.get("AGENTSEA_SERVER")
59
- env_auth_server = os.environ.get("NEBU_AUTH_SERVER") or os.environ.get(
60
- "AGENTSEA_AUTH_SERVER"
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
- import IPython # Now safe to import
79
+ # Fix: Import get_ipython directly
80
+ from IPython.core.getipython import get_ipython # Now safe to import
79
81
 
80
- ip = IPython.get_ipython()
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
- import IPython
107
+ # Fix: Import get_ipython directly
108
+ from IPython.core.getipython import get_ipython
106
109
 
107
- ip = IPython.get_ipython()
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], "lineno", start_lineno + 1
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 | Callable[[Any], Any]:
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
- print("[DEBUG Decorator] Input type identified as direct Message type.")
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
- # Check 3: Regex fallback might be less reliable now, but keep as last resort?
737
- elif (
738
- origin is None and param_type is not None
739
- ): # Only if origin failed and type exists
740
- # ... (existing regex fallback logic using param_type_str_repr) ...
741
- pass # Keep existing regex logic here if desired
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
- if content_type and hasattr(content_type, "__name__"):
933
- content_type_name = None
934
- # Check if content_type is a class before accessing __name__
935
- if isinstance(content_type, type):
936
- content_type_name = content_type.__name__
937
- all_env.append(
938
- V1EnvVar(key="CONTENT_TYPE_NAME", value=content_type_name)
939
- )
940
- else:
941
- # Handle unresolved types / typevars if needed
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: Content type '{content_type}' is not a class, cannot get name."
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: BaseModel, wait: bool = False) -> Dict[str, Any]:
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: BaseModel, wait: bool = False, logs: bool = False
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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nebu
3
- Version: 0.1.52
3
+ Version: 0.1.55
4
4
  Summary: A globally distributed container runtime
5
5
  Requires-Python: >=3.10.14
6
6
  Description-Content-Type: text/markdown
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