nebu 0.1.51__tar.gz → 0.1.53__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.51/src/nebu.egg-info → nebu-0.1.53}/PKG-INFO +1 -1
  2. {nebu-0.1.51 → nebu-0.1.53}/pyproject.toml +1 -1
  3. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/processors/consumer.py +7 -5
  4. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/processors/decorate.py +202 -72
  5. {nebu-0.1.51 → nebu-0.1.53/src/nebu.egg-info}/PKG-INFO +1 -1
  6. {nebu-0.1.51 → nebu-0.1.53}/LICENSE +0 -0
  7. {nebu-0.1.51 → nebu-0.1.53}/README.md +0 -0
  8. {nebu-0.1.51 → nebu-0.1.53}/setup.cfg +0 -0
  9. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/__init__.py +0 -0
  10. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/auth.py +0 -0
  11. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/builders/builder.py +0 -0
  12. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/builders/models.py +0 -0
  13. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/cache.py +0 -0
  14. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/config.py +0 -0
  15. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/containers/container.py +0 -0
  16. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/containers/decorator.py +0 -0
  17. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/containers/models.py +0 -0
  18. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/containers/server.py +0 -0
  19. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/data.py +0 -0
  20. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/meta.py +0 -0
  21. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/processors/default.py +0 -0
  22. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/processors/models.py +0 -0
  23. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/processors/processor.py +0 -0
  24. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/processors/remote.py +0 -0
  25. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/redis/models.py +0 -0
  26. {nebu-0.1.51 → nebu-0.1.53}/src/nebu/services/service.py +0 -0
  27. {nebu-0.1.51 → nebu-0.1.53}/src/nebu.egg-info/SOURCES.txt +0 -0
  28. {nebu-0.1.51 → nebu-0.1.53}/src/nebu.egg-info/dependency_links.txt +0 -0
  29. {nebu-0.1.51 → nebu-0.1.53}/src/nebu.egg-info/requires.txt +0 -0
  30. {nebu-0.1.51 → nebu-0.1.53}/src/nebu.egg-info/top_level.txt +0 -0
  31. {nebu-0.1.51 → nebu-0.1.53}/tests/test_containers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nebu
3
- Version: 0.1.51
3
+ Version: 0.1.53
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.51"
3
+ version = "0.1.53"
4
4
  description = "A globally distributed container runtime"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10.14"
@@ -6,7 +6,7 @@ import socket
6
6
  import sys
7
7
  import time
8
8
  import traceback
9
- import types # Added for ModuleType
9
+ import types
10
10
  from datetime import datetime, timezone
11
11
  from typing import Any, Callable, Dict, List, Optional, Tuple, TypeVar, cast
12
12
 
@@ -350,7 +350,9 @@ def process_message(message_id: str, message_data: Dict[str, str]) -> None:
350
350
  user_id = None
351
351
  try:
352
352
  payload_str = message_data.get("data")
353
- if not payload_str or not isinstance(payload_str, str):
353
+ if (
354
+ not payload_str
355
+ ): # Covers None and empty string, isinstance check is redundant
354
356
  raise ValueError(
355
357
  f"Missing or invalid 'data' field (expected non-empty string): {message_data}"
356
358
  )
@@ -724,13 +726,13 @@ try:
724
726
  assert isinstance(REDIS_STREAM, str)
725
727
  assert isinstance(REDIS_CONSUMER_GROUP, str)
726
728
 
727
- # Simplified xreadgroup call - redis-py handles encoding now
729
+ streams_arg: Dict[str, str] = {REDIS_STREAM: ">"}
730
+
728
731
  # With decode_responses=True, redis-py expects str types here
729
- streams_arg = {REDIS_STREAM: ">"}
730
732
  messages = r.xreadgroup(
731
733
  REDIS_CONSUMER_GROUP,
732
734
  consumer_name,
733
- streams_arg,
735
+ streams_arg, # type: ignore[arg-type]
734
736
  count=1,
735
737
  block=5000, # Use milliseconds for block
736
738
  )
@@ -1,11 +1,8 @@
1
1
  import ast # For parsing notebook code
2
2
  import inspect
3
- import json # Add json import
4
- import os # Add os import
5
- import re # Import re for fallback check
6
- import tempfile # Add tempfile import
3
+ import os
4
+ import re # Added import
7
5
  import textwrap
8
- import uuid # Add uuid import
9
6
  from typing import (
10
7
  Any,
11
8
  Callable,
@@ -17,15 +14,15 @@ from typing import (
17
14
  get_origin,
18
15
  get_type_hints,
19
16
  )
20
- from urllib.parse import urlparse # Add urlparse import
17
+ from urllib.parse import urlparse
21
18
 
22
- import dill # Add dill import
23
- import requests # Add requests import
24
- from botocore.exceptions import ClientError # Import ClientError
19
+ import dill
20
+ import requests
21
+ from botocore.exceptions import ClientError
25
22
  from pydantic import BaseModel
26
23
 
27
- from nebu.auth import get_user_profile # Import get_user_profile
28
- from nebu.config import GlobalConfig # Add this import
24
+ from nebu.auth import get_user_profile
25
+ from nebu.config import GlobalConfig
29
26
  from nebu.containers.models import (
30
27
  V1AuthzConfig,
31
28
  V1ContainerHealthCheck,
@@ -38,7 +35,7 @@ from nebu.containers.models import (
38
35
  V1VolumeDriver,
39
36
  V1VolumePath,
40
37
  )
41
- from nebu.data import Bucket # Import Bucket
38
+ from nebu.data import Bucket
42
39
  from nebu.meta import V1ResourceMetaRequest
43
40
  from nebu.processors.models import (
44
41
  Message,
@@ -79,10 +76,11 @@ def is_jupyter_notebook():
79
76
 
80
77
  if importlib.util.find_spec("IPython") is None:
81
78
  return False
82
- import IPython # Now safe to import
79
+ # Fix: Import get_ipython directly
80
+ from IPython.core.getipython import get_ipython # Now safe to import
83
81
 
84
- ip = IPython.get_ipython()
85
- if ip is None:
82
+ ip = get_ipython() # Use the imported function
83
+ if ip is None: # type: ignore
86
84
  # print("[DEBUG Helper] is_jupyter_notebook: No IPython instance found.")
87
85
  return False
88
86
  class_name = str(ip.__class__)
@@ -93,7 +91,9 @@ def is_jupyter_notebook():
93
91
  # print("[DEBUG Helper] is_jupyter_notebook: Not Jupyter (IPython instance found, but not ZMQInteractiveShell).")
94
92
  return False
95
93
  except Exception as e:
96
- # print(f"[DEBUG Helper] is_jupyter_notebook: Exception occurred: {e}") # Reduce verbosity
94
+ print(
95
+ f"[DEBUG Helper] is_jupyter_notebook: Exception occurred: {e}"
96
+ ) # Reduce verbosity
97
97
  return False
98
98
 
99
99
 
@@ -104,9 +104,10 @@ def get_notebook_executed_code():
104
104
  """
105
105
  print("[DEBUG Helper] Attempting to get notebook execution history...")
106
106
  try:
107
- import IPython
107
+ # Fix: Import get_ipython directly
108
+ from IPython.core.getipython import get_ipython
108
109
 
109
- ip = IPython.get_ipython()
110
+ ip = get_ipython() # Use the imported function
110
111
  if ip is None or not hasattr(ip, "history_manager"):
111
112
  print(
112
113
  "[DEBUG Helper] get_notebook_executed_code: No IPython instance or history_manager."
@@ -164,9 +165,10 @@ def extract_definition_source_from_string(
164
165
  found_in_cell = False
165
166
  for node in ast.walk(tree):
166
167
  if (
167
- isinstance(node, def_type)
168
- and hasattr(node, "name")
169
- and node.name == def_name
168
+ isinstance(
169
+ node, def_type
170
+ ) # Check if it's the right type (FuncDef or ClassDef)
171
+ and getattr(node, "name", None) == def_name # Safely check name
170
172
  ):
171
173
  print(
172
174
  f"[DEBUG Helper] extract: Found node for '{def_name}' in cell #{cell_num}."
@@ -188,10 +190,14 @@ def extract_definition_source_from_string(
188
190
  start_lineno = getattr(node, "lineno", 1) - 1
189
191
  end_lineno = getattr(node, "end_lineno", start_lineno + 1)
190
192
 
191
- if hasattr(node, "decorator_list") and node.decorator_list:
193
+ if hasattr(node, "decorator_list") and node.decorator_list: # type: ignore
194
+ # Ensure it's a node type that *can* have decorators
195
+ # FunctionDef and ClassDef have decorator_list
192
196
  first_decorator_start_line = (
193
197
  getattr(
194
- node.decorator_list[0], "lineno", start_lineno + 1
198
+ node.decorator_list[0], # type: ignore
199
+ "lineno",
200
+ start_lineno + 1,
195
201
  )
196
202
  - 1
197
203
  ) # type: ignore
@@ -598,28 +604,45 @@ def processor(
598
604
  included_sources[obj] = obj_source
599
605
  # Decide how to pass included source - keep using Env Vars for now
600
606
  env_key_base = f"INCLUDED_OBJECT_{i}"
601
- if isinstance(obj_source, str):
607
+ if isinstance(obj_source, str): # type: ignore[arg-type]
602
608
  all_env.append(
603
609
  V1EnvVar(key=f"{env_key_base}_SOURCE", value=obj_source)
604
610
  )
605
611
  # print(f"[DEBUG Decorator] Added string source to env for included obj: {obj_name_str}")
606
612
  elif isinstance(obj_source, tuple):
607
613
  # Handle tuple source (origin, args) - assumes get_model_source/get_type_source logic
608
- origin_src, arg_srcs = obj_source
609
- if origin_src and isinstance(origin_src, str):
610
- all_env.append(
611
- V1EnvVar(key=f"{env_key_base}_SOURCE", value=origin_src)
612
- )
613
- for j, arg_src in enumerate(arg_srcs):
614
- if isinstance(arg_src, str):
614
+ # Ensure obj_source is indeed a tuple before unpacking
615
+ if len(obj_source) == 2:
616
+ # Now safe to unpack
617
+ origin_src, arg_srcs = obj_source # type: ignore[misc] # Suppress persistent tuple unpacking error
618
+ # type: ignore[misc] # Suppress persistent tuple unpacking error
619
+ if origin_src and isinstance(origin_src, str):
615
620
  all_env.append(
616
621
  V1EnvVar(
617
- key=f"{env_key_base}_ARG_{j}_SOURCE",
618
- value=arg_src,
622
+ key=f"{env_key_base}_SOURCE", value=origin_src
619
623
  )
620
624
  )
621
- # Handle nested tuples if necessary, or keep it simple
622
- # print(f"[DEBUG Decorator] Added tuple source to env for included obj: {obj_name_str}")
625
+ # Handle arg_srcs (this part seems okay)
626
+ if isinstance(arg_srcs, list):
627
+ for j, arg_src in enumerate(arg_srcs):
628
+ if isinstance(arg_src, str):
629
+ all_env.append(
630
+ V1EnvVar(
631
+ key=f"{env_key_base}_ARG_{j}_SOURCE",
632
+ value=arg_src,
633
+ )
634
+ )
635
+ else:
636
+ print(
637
+ f"[DEBUG Decorator] Warning: Expected arg_srcs to be a list, got {type(arg_srcs)}"
638
+ )
639
+ else:
640
+ # Handle unexpected type or structure for obj_source if necessary
641
+ # For now, assume it fits the expected tuple structure if isinstance passes
642
+ # origin_src, arg_srcs = None, [] # Default/error state (already covered by outer check)
643
+ print(
644
+ f"[DEBUG Decorator] Warning: Unexpected obj_source structure: {obj_source}"
645
+ )
623
646
  else:
624
647
  print(
625
648
  f"Warning: Unknown source type for included object {obj_name_str}: {type(obj_source)}"
@@ -690,6 +713,7 @@ def processor(
690
713
  print(f"[DEBUG Decorator] get_origin result: {origin}, get_args result: {args}")
691
714
  is_stream_message = False
692
715
  content_type = None
716
+ content_type_name_from_regex = None # Store regex result here
693
717
 
694
718
  # Use Message class directly for comparison
695
719
  message_cls = Message # Get the class object
@@ -709,18 +733,63 @@ def processor(
709
733
  )
710
734
  else:
711
735
  print(
712
- "[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."
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."
713
770
  )
771
+ is_stream_message = False
772
+ content_type = None
714
773
  # Check 2: Direct type check (Handles cases where get_origin might fail but type is correct)
715
774
  elif isinstance(param_type, type) and param_type is message_cls:
716
- 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
+ )
717
779
  is_stream_message = True
718
- # Check 3: Regex fallback might be less reliable now, but keep as last resort?
719
- elif (
720
- origin is None and param_type is not None
721
- ): # Only if origin failed and type exists
722
- # ... (existing regex fallback logic using param_type_str_repr) ...
723
- 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
724
793
 
725
794
  else: # Handle cases where param_type might be None or origin is something else
726
795
  print(
@@ -826,19 +895,44 @@ def processor(
826
895
  # Add: Included object sources (if any)
827
896
  # Add: INIT_FUNC_NAME (if provided)
828
897
 
829
- # Basic info needed by consumer to find and run the function
830
- all_env.append(V1EnvVar(key="FUNCTION_NAME", value=processor_name))
898
+ # Calculate module_path based on relative file path
899
+ calculated_module_path = None
831
900
  if rel_func_path:
832
901
  # Convert OS-specific path to module path (e.g., subdir/file.py -> subdir.file)
833
- module_path = rel_func_path.replace(os.sep, ".")
834
- if module_path.endswith(".py"):
835
- module_path = module_path[:-3]
836
- # Handle __init__.py -> treat as package name
837
- if module_path.endswith(".__init__"):
838
- module_path = module_path[: -len(".__init__")]
839
- elif module_path == "__init__": # Top-level __init__.py
840
- module_path = "" # Or handle differently? Let's assume it means import '.'? Maybe error?
902
+ base, ext = os.path.splitext(rel_func_path)
903
+ if ext == ".py":
904
+ module_path_parts = base.split(os.sep)
905
+ if module_path_parts[-1] == "__init__":
906
+ module_path_parts.pop() # Remove __init__
907
+ # Filter out potential empty strings if path started with / or had //
908
+ module_path_parts = [part for part in module_path_parts if part]
909
+ calculated_module_path = ".".join(module_path_parts)
910
+ else:
911
+ # Not a python file? Should not happen based on inspect.getfile
912
+ print(
913
+ f"[DEBUG Decorator] Warning: Function source file is not a .py file: {rel_func_path}"
914
+ )
915
+ # Set calculated_module_path to None explicitly to trigger fallback later
916
+ calculated_module_path = None
917
+ else:
918
+ # Should have errored earlier if rel_func_path is None
919
+ print(
920
+ "[DEBUG Decorator] Warning: Could not determine relative function path. Falling back to func.__module__."
921
+ )
922
+ # Set calculated_module_path to None explicitly to trigger fallback later
923
+ calculated_module_path = None
924
+
925
+ # Assign final module_path using fallback if calculation failed or wasn't applicable
926
+ if calculated_module_path is not None:
927
+ module_path = calculated_module_path
928
+ print(f"[DEBUG Decorator] Using calculated module path: {module_path}")
929
+ else:
930
+ module_path = func.__module__ # Fallback
931
+ print(f"[DEBUG Decorator] Falling back to func.__module__: {module_path}")
841
932
 
933
+ # Basic info needed by consumer to find and run the function
934
+ all_env.append(V1EnvVar(key="FUNCTION_NAME", value=processor_name))
935
+ if rel_func_path:
842
936
  # For now, just pass the relative file path, consumer will handle conversion
843
937
  all_env.append(
844
938
  V1EnvVar(key="NEBU_ENTRYPOINT_MODULE_PATH", value=rel_func_path)
@@ -846,9 +940,7 @@ def processor(
846
940
  print(
847
941
  f"[DEBUG Decorator] Set NEBU_ENTRYPOINT_MODULE_PATH to: {rel_func_path}"
848
942
  )
849
- else:
850
- # Should have errored earlier if rel_func_path is None
851
- raise RuntimeError("Internal error: Relative function path not determined.")
943
+ # No else needed, handled by fallback calculation above
852
944
 
853
945
  if init_func:
854
946
  init_func_name = init_func.__name__ # Get name here
@@ -862,26 +954,64 @@ def processor(
862
954
  print(f"[DEBUG Decorator] Set INIT_FUNC_NAME to: {init_func_name}")
863
955
 
864
956
  # Type info (still useful for deserialization/validation in consumer)
957
+ # Adjust type strings to replace '__main__' with the calculated module path
958
+ param_type_str_repr = str(param_type)
959
+ if module_path != "__main__" and "__main__." in param_type_str_repr:
960
+ # Be careful with replacement - replace only module prefix
961
+ # Example: "<class '__main__.MyModel'>" -> "<class 'mymodule.MyModel'>"
962
+ # Example: "typing.Optional[__main__.MyModel]" -> "typing.Optional[mymodule.MyModel]"
963
+ param_type_str_repr = param_type_str_repr.replace(
964
+ "__main__.", f"{module_path}."
965
+ )
966
+ print(
967
+ f"[DEBUG Decorator] Adjusted param type string: {param_type_str_repr}"
968
+ )
969
+
865
970
  all_env.append(V1EnvVar(key="PARAM_TYPE_STR", value=param_type_str_repr))
866
- all_env.append(
867
- V1EnvVar(key="RETURN_TYPE_STR", value=return_type_str_repr)
868
- ) # Use repr
971
+
972
+ return_type_str_repr = str(return_type)
973
+ if module_path != "__main__" and "__main__." in return_type_str_repr:
974
+ return_type_str_repr = return_type_str_repr.replace(
975
+ "__main__.", f"{module_path}."
976
+ )
977
+ print(
978
+ f"[DEBUG Decorator] Adjusted return type string: {return_type_str_repr}"
979
+ )
980
+
981
+ all_env.append(V1EnvVar(key="RETURN_TYPE_STR", value=return_type_str_repr))
869
982
  all_env.append(V1EnvVar(key="IS_STREAM_MESSAGE", value=str(is_stream_message)))
870
- if content_type and hasattr(content_type, "__name__"):
871
- # Check if content_type is a class before accessing __name__
872
- if isinstance(content_type, type):
873
- all_env.append(
874
- V1EnvVar(key="CONTENT_TYPE_NAME", value=content_type.__name__)
875
- )
876
- else:
877
- # 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:
878
999
  print(
879
- 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."
880
1001
  )
881
- # MODULE_NAME might be less reliable now, depends on where func is defined relative to project root
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
+
1008
+ # Use the calculated module_path for MODULE_NAME
882
1009
  all_env.append(
883
- V1EnvVar(key="MODULE_NAME", value=func.__module__)
884
- ) # Keep for potential debugging/info
1010
+ V1EnvVar(
1011
+ key="MODULE_NAME", value=module_path
1012
+ ) # module_path is guaranteed to be a string here (calculated or fallback)
1013
+ )
1014
+ print(f"[DEBUG Decorator] Set MODULE_NAME to: {module_path}")
885
1015
 
886
1016
  # Add PYTHONPATH
887
1017
  pythonpath_value = CONTAINER_CODE_DIR
@@ -1016,7 +1146,7 @@ def processor(
1016
1146
  # setattr(processor_instance, 'original_func', func) # Use setattr if not in model
1017
1147
  try:
1018
1148
  # This will fail if Processor hasn't been updated to include this field
1019
- processor_instance.original_func = func
1149
+ processor_instance.original_func = func # type: ignore
1020
1150
  except AttributeError:
1021
1151
  print(
1022
1152
  "Warning: Could not assign original_func to Processor instance. Update Processor model or remove assignment."
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nebu
3
- Version: 0.1.51
3
+ Version: 0.1.53
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
File without changes