iris-pex-embedded-python 3.5.5b4__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.
Files changed (91) hide show
  1. grongier/__init__.py +0 -0
  2. grongier/cls/Grongier/PEX/BusinessOperation.cls +8 -0
  3. grongier/cls/Grongier/PEX/BusinessProcess.cls +13 -0
  4. grongier/cls/Grongier/PEX/BusinessService.cls +8 -0
  5. grongier/cls/Grongier/PEX/Common.cls +10 -0
  6. grongier/cls/Grongier/PEX/Director.cls +10 -0
  7. grongier/cls/Grongier/PEX/Duplex/Operation.cls +4 -0
  8. grongier/cls/Grongier/PEX/Duplex/Process.cls +13 -0
  9. grongier/cls/Grongier/PEX/Duplex/Service.cls +4 -0
  10. grongier/cls/Grongier/PEX/InboundAdapter.cls +8 -0
  11. grongier/cls/Grongier/PEX/Message.cls +13 -0
  12. grongier/cls/Grongier/PEX/OutboundAdapter.cls +8 -0
  13. grongier/cls/Grongier/PEX/PickleMessage.cls +13 -0
  14. grongier/cls/Grongier/PEX/PrivateSession/Duplex.cls +8 -0
  15. grongier/cls/Grongier/PEX/PrivateSession/Message/Ack.cls +14 -0
  16. grongier/cls/Grongier/PEX/PrivateSession/Message/Poll.cls +14 -0
  17. grongier/cls/Grongier/PEX/PrivateSession/Message/Start.cls +14 -0
  18. grongier/cls/Grongier/PEX/PrivateSession/Message/Stop.cls +14 -0
  19. grongier/cls/Grongier/PEX/Test.cls +10 -0
  20. grongier/cls/Grongier/PEX/Utils.cls +10 -0
  21. grongier/cls/Grongier/Service/WSGI.cls +4 -0
  22. grongier/pex/__init__.py +24 -0
  23. grongier/pex/__main__.py +4 -0
  24. grongier/pex/_business_host.py +1 -0
  25. grongier/pex/_cli.py +4 -0
  26. grongier/pex/_common.py +1 -0
  27. grongier/pex/_director.py +1 -0
  28. grongier/pex/_utils.py +1 -0
  29. grongier/pex/wsgi/handlers.py +104 -0
  30. iop/__init__.py +25 -0
  31. iop/__main__.py +4 -0
  32. iop/_async_request.py +67 -0
  33. iop/_business_host.py +256 -0
  34. iop/_business_operation.py +75 -0
  35. iop/_business_process.py +224 -0
  36. iop/_business_service.py +63 -0
  37. iop/_cli.py +247 -0
  38. iop/_common.py +334 -0
  39. iop/_debugpy.py +187 -0
  40. iop/_decorators.py +49 -0
  41. iop/_director.py +301 -0
  42. iop/_dispatch.py +136 -0
  43. iop/_generator_request.py +30 -0
  44. iop/_inbound_adapter.py +34 -0
  45. iop/_iris.py +8 -0
  46. iop/_log_manager.py +100 -0
  47. iop/_message.py +40 -0
  48. iop/_message_validator.py +49 -0
  49. iop/_outbound_adapter.py +23 -0
  50. iop/_private_session_duplex.py +103 -0
  51. iop/_private_session_process.py +41 -0
  52. iop/_remote.py +91 -0
  53. iop/_serialization.py +199 -0
  54. iop/_utils.py +671 -0
  55. iop/cls/IOP/BusinessOperation.cls +35 -0
  56. iop/cls/IOP/BusinessProcess.cls +156 -0
  57. iop/cls/IOP/BusinessService.cls +40 -0
  58. iop/cls/IOP/Common.cls +569 -0
  59. iop/cls/IOP/Director.cls +70 -0
  60. iop/cls/IOP/Duplex/Operation.cls +29 -0
  61. iop/cls/IOP/Duplex/Process.cls +229 -0
  62. iop/cls/IOP/Duplex/Service.cls +9 -0
  63. iop/cls/IOP/Generator/Message/Ack.cls +31 -0
  64. iop/cls/IOP/Generator/Message/Poll.cls +31 -0
  65. iop/cls/IOP/Generator/Message/Start.cls +15 -0
  66. iop/cls/IOP/Generator/Message/StartPickle.cls +15 -0
  67. iop/cls/IOP/Generator/Message/Stop.cls +32 -0
  68. iop/cls/IOP/InboundAdapter.cls +22 -0
  69. iop/cls/IOP/Message/JSONSchema.cls +125 -0
  70. iop/cls/IOP/Message.cls +754 -0
  71. iop/cls/IOP/OutboundAdapter.cls +36 -0
  72. iop/cls/IOP/PickleMessage.cls +58 -0
  73. iop/cls/IOP/PrivateSession/Duplex.cls +260 -0
  74. iop/cls/IOP/PrivateSession/Message/Ack.cls +32 -0
  75. iop/cls/IOP/PrivateSession/Message/Poll.cls +32 -0
  76. iop/cls/IOP/PrivateSession/Message/Start.cls +31 -0
  77. iop/cls/IOP/PrivateSession/Message/Stop.cls +48 -0
  78. iop/cls/IOP/Projection.cls +49 -0
  79. iop/cls/IOP/Service/Remote/Handler.cls +30 -0
  80. iop/cls/IOP/Service/Remote/Rest/v1.cls +97 -0
  81. iop/cls/IOP/Service/WSGI.cls +310 -0
  82. iop/cls/IOP/Test.cls +85 -0
  83. iop/cls/IOP/Utils.cls +503 -0
  84. iop/cls/IOP/Wrapper.cls +58 -0
  85. iop/wsgi/handlers.py +104 -0
  86. iris_pex_embedded_python-3.5.5b4.dist-info/METADATA +91 -0
  87. iris_pex_embedded_python-3.5.5b4.dist-info/RECORD +91 -0
  88. iris_pex_embedded_python-3.5.5b4.dist-info/WHEEL +5 -0
  89. iris_pex_embedded_python-3.5.5b4.dist-info/entry_points.txt +2 -0
  90. iris_pex_embedded_python-3.5.5b4.dist-info/licenses/LICENSE +21 -0
  91. iris_pex_embedded_python-3.5.5b4.dist-info/top_level.txt +2 -0
iop/_serialization.py ADDED
@@ -0,0 +1,199 @@
1
+ from __future__ import annotations
2
+ import codecs
3
+ import importlib
4
+ import inspect
5
+ import pickle
6
+ import json
7
+ from dataclasses import is_dataclass
8
+ from typing import Any, Dict, Type
9
+
10
+ from pydantic import BaseModel, TypeAdapter, ValidationError
11
+
12
+ from . import _iris
13
+ from ._message import _PydanticPickleMessage, _Message
14
+ from ._utils import _Utils
15
+
16
+ class SerializationError(Exception):
17
+ """Exception raised for serialization errors."""
18
+ pass
19
+
20
+ class TempPydanticModel(BaseModel):
21
+ model_config = {
22
+ 'arbitrary_types_allowed' : True,
23
+ 'extra' : 'allow'
24
+ }
25
+
26
+ class MessageSerializer:
27
+ """Handles message serialization and deserialization."""
28
+
29
+ @staticmethod
30
+ def serialize(message: Any, use_pickle: bool = False, is_generator:bool = False) -> Any:
31
+ """Serializes a message to IRIS format."""
32
+ message = remove_iris_id(message)
33
+ if use_pickle:
34
+ return MessageSerializer._serialize_pickle(message, is_generator)
35
+ return MessageSerializer._serialize_json(message, is_generator)
36
+
37
+ @staticmethod
38
+ def _serialize_json(message: Any, is_generator: bool = False) -> Any:
39
+ json_string = MessageSerializer._convert_to_json_safe(message)
40
+
41
+ if is_generator:
42
+ msg = _iris.get_iris().cls('IOP.Generator.Message.Start')._New()
43
+ else:
44
+ msg = _iris.get_iris().cls('IOP.Message')._New()
45
+ msg.classname = f"{message.__class__.__module__}.{message.__class__.__name__}"
46
+
47
+ if hasattr(msg, 'buffer') and len(json_string) > msg.buffer:
48
+ msg.json = _Utils.string_to_stream(json_string, msg.buffer)
49
+ else:
50
+ msg.json = json_string
51
+ return msg
52
+
53
+ @staticmethod
54
+ def _serialize_pickle(message: Any, is_generator: bool = False) -> Any:
55
+ """Serializes a message to IRIS format using pickle."""
56
+ message = remove_iris_id(message)
57
+ pickle_string = codecs.encode(pickle.dumps(message), "base64").decode()
58
+ if is_generator:
59
+ msg = _iris.get_iris().cls('IOP.Generator.Message.StartPickle')._New()
60
+ else:
61
+ msg = _iris.get_iris().cls('IOP.PickleMessage')._New()
62
+ msg.classname = f"{message.__class__.__module__}.{message.__class__.__name__}"
63
+ msg.jstr = _Utils.string_to_stream(pickle_string)
64
+ return msg
65
+
66
+ @staticmethod
67
+ def deserialize(serial: Any, use_pickle: bool = False) -> Any:
68
+ if use_pickle:
69
+ msg=MessageSerializer._deserialize_pickle(serial)
70
+ else:
71
+ msg=MessageSerializer._deserialize_json(serial)
72
+
73
+ try:
74
+ iris_id = serial._Id()
75
+ msg._iris_id = iris_id if iris_id else None
76
+ except Exception as e:
77
+ pass
78
+
79
+ return msg
80
+
81
+ @staticmethod
82
+ def _deserialize_json(serial: Any) -> Any:
83
+ if not serial.classname:
84
+ raise SerializationError("JSON message malformed, must include classname")
85
+
86
+ try:
87
+ module_name, class_name = MessageSerializer._parse_classname(serial.classname)
88
+ module = importlib.import_module(module_name)
89
+ msg_class = getattr(module, class_name)
90
+ except Exception as e:
91
+ raise SerializationError(f"Failed to load class {serial.classname}: {str(e)}")
92
+
93
+ json_string = (_Utils.stream_to_string(serial.json)
94
+ if serial.type == 'Stream' else serial.json)
95
+
96
+ try:
97
+ if issubclass(msg_class, BaseModel):
98
+ return msg_class.model_validate_json(json_string)
99
+ elif is_dataclass(msg_class):
100
+ return dataclass_from_dict(msg_class, json.loads(json_string))
101
+ else:
102
+ raise SerializationError(f"Class {msg_class} must be a Pydantic model or dataclass")
103
+ except Exception as e:
104
+ raise SerializationError(f"Failed to deserialize JSON: {str(e)}")
105
+
106
+ @staticmethod
107
+ def _deserialize_pickle(serial: Any) -> Any:
108
+ string = _Utils.stream_to_string(serial.jstr)
109
+ return pickle.loads(codecs.decode(string.encode(), "base64"))
110
+
111
+ @staticmethod
112
+ def _parse_classname(classname: str) -> tuple[str, str]:
113
+ j = classname.rindex(".")
114
+ if j <= 0:
115
+ raise SerializationError(f"Classname must include a module: {classname}")
116
+ return classname[:j], classname[j+1:]
117
+
118
+ @staticmethod
119
+ def _convert_to_json_safe(obj: Any) -> Any:
120
+ """Convert objects to JSON-safe format."""
121
+ if isinstance(obj, BaseModel):
122
+ return obj.model_dump_json()
123
+ elif is_dataclass(obj) and isinstance(obj, _Message):
124
+ return TempPydanticModel.model_validate(dataclass_to_dict(obj)).model_dump_json()
125
+ else:
126
+ raise SerializationError(f"Object {obj} must be a Pydantic model or dataclass Message")
127
+
128
+
129
+ def remove_iris_id(message: Any) -> Any:
130
+ try:
131
+ del message._iris_id
132
+ except AttributeError:
133
+ pass
134
+ return message
135
+
136
+ def dataclass_from_dict(klass: Type | Any, dikt: Dict) -> Any:
137
+ """Converts a dictionary to a dataclass instance.
138
+ Handles non attended fields and nested dataclasses."""
139
+
140
+ def process_field(value: Any, field_type: Type) -> Any:
141
+ if value is None:
142
+ return None
143
+ if is_dataclass(field_type):
144
+ return dataclass_from_dict(field_type, value)
145
+ if field_type != inspect.Parameter.empty:
146
+ try:
147
+ return TypeAdapter(field_type).validate_python(value)
148
+ except ValidationError:
149
+ return value
150
+ return value
151
+
152
+ # Get field definitions from class signature
153
+ fields = inspect.signature(klass).parameters
154
+ field_dict = {}
155
+
156
+ # Process each field
157
+ for field_name, field_info in fields.items():
158
+ if field_name not in dikt:
159
+ if field_info.default != field_info.empty:
160
+ field_dict[field_name] = field_info.default
161
+ continue
162
+
163
+ field_dict[field_name] = process_field(dikt[field_name], field_info.annotation)
164
+
165
+ # Create instance
166
+ instance = klass(**field_dict)
167
+
168
+ # Add any extra fields not in the dataclass definition
169
+ for key, value in dikt.items():
170
+ if key not in field_dict:
171
+ setattr(instance, key, value)
172
+
173
+ return instance
174
+
175
+ def dataclass_to_dict(instance: Any) -> Dict:
176
+ """Converts a class instance to a dictionary.
177
+ Handles non attended fields."""
178
+ result = {}
179
+ for field in instance.__dict__:
180
+ value = getattr(instance, field)
181
+ if is_dataclass(value):
182
+ result[field] = dataclass_to_dict(value)
183
+ elif isinstance(value, list):
184
+ result[field] = [dataclass_to_dict(i) if is_dataclass(i) else i for i in value]
185
+ elif isinstance(value, dict):
186
+ result[field] = {k: dataclass_to_dict(v) if is_dataclass(v) else v for k, v in value.items()}
187
+ elif hasattr(value, '__dict__'):
188
+ result[field] = dataclass_to_dict(value)
189
+ else:
190
+ result[field] = value
191
+ return result
192
+
193
+ # Maintain backwards compatibility
194
+ serialize_pickle_message = lambda msg: MessageSerializer.serialize(msg, use_pickle=True, is_generator=False)
195
+ serialize_pickle_message_generator = lambda msg: MessageSerializer.serialize(msg, use_pickle=True, is_generator=True)
196
+ serialize_message = lambda msg: MessageSerializer.serialize(msg, use_pickle=False, is_generator=False)
197
+ serialize_message_generator = lambda msg: MessageSerializer.serialize(msg, use_pickle=False, is_generator=True)
198
+ deserialize_pickle_message = lambda serial: MessageSerializer.deserialize(serial, use_pickle=True)
199
+ deserialize_message = lambda serial: MessageSerializer.deserialize(serial, use_pickle=False)