xian-tech-runtime-types 0.1.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.
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: xian-tech-runtime-types
3
+ Version: 0.1.0
4
+ Summary: Shared deterministic runtime types for the Xian stack
5
+ Author-email: Xian Network <info@xian.org>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+
10
+ # xian-tech-runtime-types
11
+
12
+ Shared deterministic runtime types for the Xian stack.
@@ -0,0 +1,3 @@
1
+ # xian-tech-runtime-types
2
+
3
+ Shared deterministic runtime types for the Xian stack.
@@ -0,0 +1,18 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "xian-tech-runtime-types"
7
+ version = "0.1.0"
8
+ description = "Shared deterministic runtime types for the Xian stack"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ authors = [{ name = "Xian Network", email = "info@xian.org" }]
12
+ requires-python = ">=3.11"
13
+
14
+ [tool.setuptools]
15
+ package-dir = {"" = "src"}
16
+
17
+ [tool.setuptools.packages.find]
18
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,71 @@
1
+ from xian_runtime_types.decimal import (
2
+ CONTEXT,
3
+ MAX_DECIMAL,
4
+ MAX_LOWER_PRECISION,
5
+ MAX_UPPER_PRECISION,
6
+ MIN_DECIMAL,
7
+ ContractingDecimal,
8
+ DecimalOverflowError,
9
+ exports,
10
+ fix_precision,
11
+ neg_sci_not,
12
+ )
13
+ from xian_runtime_types.encoding import (
14
+ Encoder,
15
+ as_object,
16
+ convert,
17
+ convert_dict,
18
+ decode,
19
+ decode_kv,
20
+ encode,
21
+ encode_int,
22
+ encode_ints_in_dict,
23
+ encode_kv,
24
+ safe_repr,
25
+ )
26
+ from xian_runtime_types.time import (
27
+ DAYS,
28
+ HOURS,
29
+ MINUTES,
30
+ SECONDS,
31
+ WEEKS,
32
+ Datetime,
33
+ Timedelta,
34
+ datetime_module,
35
+ get_raw_seconds,
36
+ to_contract_time,
37
+ )
38
+
39
+ __all__ = [
40
+ "CONTEXT",
41
+ "MAX_DECIMAL",
42
+ "MAX_LOWER_PRECISION",
43
+ "MAX_UPPER_PRECISION",
44
+ "MIN_DECIMAL",
45
+ "ContractingDecimal",
46
+ "DecimalOverflowError",
47
+ "exports",
48
+ "fix_precision",
49
+ "neg_sci_not",
50
+ "Encoder",
51
+ "as_object",
52
+ "convert",
53
+ "convert_dict",
54
+ "decode",
55
+ "decode_kv",
56
+ "encode",
57
+ "encode_int",
58
+ "encode_ints_in_dict",
59
+ "encode_kv",
60
+ "safe_repr",
61
+ "DAYS",
62
+ "HOURS",
63
+ "MINUTES",
64
+ "SECONDS",
65
+ "WEEKS",
66
+ "Datetime",
67
+ "Timedelta",
68
+ "datetime_module",
69
+ "get_raw_seconds",
70
+ "to_contract_time",
71
+ ]
@@ -0,0 +1,203 @@
1
+ import decimal
2
+ from decimal import ROUND_DOWN, Context, Decimal, InvalidOperation
3
+
4
+ MAX_UPPER_PRECISION = 61
5
+ MAX_LOWER_PRECISION = 30
6
+
7
+ CONTEXT = Context(
8
+ prec=MAX_UPPER_PRECISION + MAX_LOWER_PRECISION,
9
+ rounding=ROUND_DOWN,
10
+ Emin=-100,
11
+ Emax=100,
12
+ )
13
+ decimal.setcontext(CONTEXT)
14
+
15
+
16
+ def make_min_decimal_str(prec):
17
+ return "0." + "0" * (prec - 1) + "1"
18
+
19
+
20
+ def make_max_decimal_str(upper_prec, lower_prec=0):
21
+ whole = "9" * upper_prec
22
+ if lower_prec <= 0:
23
+ return whole
24
+ return f"{whole}.{'9' * lower_prec}"
25
+
26
+
27
+ def neg_sci_not(s: str):
28
+ try:
29
+ base, exp = s.split("e-")
30
+ if float(base) > 9:
31
+ return s
32
+
33
+ base = base.replace(".", "")
34
+ numbers = ("0" * (int(exp) - 1)) + base
35
+
36
+ if int(exp) > 0:
37
+ numbers = "0." + numbers
38
+
39
+ return numbers
40
+ except ValueError:
41
+ return s
42
+
43
+
44
+ MAX_DECIMAL = Decimal(
45
+ make_max_decimal_str(MAX_UPPER_PRECISION, MAX_LOWER_PRECISION)
46
+ )
47
+ MIN_DECIMAL = Decimal(make_min_decimal_str(MAX_LOWER_PRECISION))
48
+
49
+
50
+ class DecimalOverflowError(OverflowError):
51
+ pass
52
+
53
+
54
+ def fix_precision(x: Decimal):
55
+ try:
56
+ quantized = x.quantize(MIN_DECIMAL, rounding=ROUND_DOWN).normalize()
57
+ except InvalidOperation as exc:
58
+ raise DecimalOverflowError(
59
+ f"Value {x} exceeds the supported decimal range."
60
+ ) from exc
61
+ if quantized == 0:
62
+ return Decimal("0")
63
+ if quantized > MAX_DECIMAL or quantized < -MAX_DECIMAL:
64
+ raise DecimalOverflowError(
65
+ f"Value {x} exceeds the supported decimal range."
66
+ )
67
+ return quantized
68
+
69
+
70
+ class ContractingDecimal:
71
+ def _get_other(self, other):
72
+ if isinstance(other, ContractingDecimal):
73
+ return other._d
74
+ elif isinstance(other, (float, int)):
75
+ return fix_precision(Decimal(neg_sci_not(str(other))))
76
+ return other
77
+
78
+ def __init__(self, a):
79
+ if isinstance(a, (float, int)):
80
+ self._d = Decimal(neg_sci_not(str(a)))
81
+ elif isinstance(a, str):
82
+ self._d = Decimal(neg_sci_not(a))
83
+ elif isinstance(a, Decimal):
84
+ self._d = a
85
+ else:
86
+ self._d = Decimal(a)
87
+
88
+ self._d = fix_precision(self._d)
89
+
90
+ def __bool__(self):
91
+ return self._d != 0
92
+
93
+ def __eq__(self, other):
94
+ return self._d == self._get_other(other)
95
+
96
+ def __lt__(self, other):
97
+ return self._d < self._get_other(other)
98
+
99
+ def __le__(self, other):
100
+ return self._d <= self._get_other(other)
101
+
102
+ def __gt__(self, other):
103
+ return self._d > self._get_other(other)
104
+
105
+ def __ge__(self, other):
106
+ return self._d >= self._get_other(other)
107
+
108
+ def __str__(self):
109
+ return self._d.to_eng_string()
110
+
111
+ def __repr__(self):
112
+ return self._d.to_eng_string()
113
+
114
+ def __neg__(self):
115
+ return ContractingDecimal(-self._d)
116
+
117
+ def __pos__(self):
118
+ return self
119
+
120
+ def __abs__(self):
121
+ return ContractingDecimal(abs(self._d))
122
+
123
+ def __add__(self, other):
124
+ return ContractingDecimal(
125
+ fix_precision(self._d + self._get_other(other))
126
+ )
127
+
128
+ def __radd__(self, other):
129
+ return ContractingDecimal(
130
+ fix_precision(self._get_other(other) + self._d)
131
+ )
132
+
133
+ def __sub__(self, other):
134
+ return ContractingDecimal(
135
+ fix_precision(self._d - self._get_other(other))
136
+ )
137
+
138
+ def __rsub__(self, other):
139
+ return ContractingDecimal(
140
+ fix_precision(self._get_other(other) - self._d)
141
+ )
142
+
143
+ def __mul__(self, other):
144
+ return ContractingDecimal(
145
+ fix_precision(self._d * self._get_other(other))
146
+ )
147
+
148
+ def __rmul__(self, other):
149
+ return ContractingDecimal(
150
+ fix_precision(self._get_other(other) * self._d)
151
+ )
152
+
153
+ def __truediv__(self, other):
154
+ return ContractingDecimal(
155
+ fix_precision(self._d / self._get_other(other))
156
+ )
157
+
158
+ def __rtruediv__(self, other):
159
+ return ContractingDecimal(
160
+ fix_precision(self._get_other(other) / self._d)
161
+ )
162
+
163
+ def __mod__(self, other):
164
+ return ContractingDecimal(
165
+ fix_precision(self._d % self._get_other(other))
166
+ )
167
+
168
+ def __rmod__(self, other):
169
+ return ContractingDecimal(
170
+ fix_precision(self._get_other(other) % self._d)
171
+ )
172
+
173
+ def __floordiv__(self, other):
174
+ return ContractingDecimal(
175
+ fix_precision(self._d // self._get_other(other))
176
+ )
177
+
178
+ def __rfloordiv__(self, other):
179
+ return ContractingDecimal(
180
+ fix_precision(self._get_other(other) // self._d)
181
+ )
182
+
183
+ def __pow__(self, other):
184
+ return ContractingDecimal(
185
+ fix_precision(self._d ** self._get_other(other))
186
+ )
187
+
188
+ def __rpow__(self, other):
189
+ return ContractingDecimal(
190
+ fix_precision(self._get_other(other) ** self._d)
191
+ )
192
+
193
+ def __int__(self):
194
+ return int(self._d)
195
+
196
+ def __float__(self):
197
+ return float(self._d)
198
+
199
+ def __round__(self, n=None):
200
+ return round(self._d, n)
201
+
202
+
203
+ exports = {"decimal": ContractingDecimal}
@@ -0,0 +1,163 @@
1
+ import decimal
2
+ import json
3
+
4
+ from xian_runtime_types.decimal import ContractingDecimal, fix_precision
5
+ from xian_runtime_types.time import Datetime, Timedelta
6
+
7
+ MIN_INT = -(2**63)
8
+ MAX_INT = 2**63 - 1
9
+ TYPES = {"__fixed__", "__delta__", "__bytes__", "__time__", "__big_int__"}
10
+
11
+
12
+ def safe_repr(obj, max_len=1024):
13
+ try:
14
+ raw = obj.__repr__()
15
+ parts = raw.split(" at 0x")
16
+ if len(parts) > 1:
17
+ return parts[0] + ">"
18
+ return parts[0][:max_len]
19
+ except Exception:
20
+ return None
21
+
22
+
23
+ class Encoder(json.JSONEncoder):
24
+ def default(self, value, *args):
25
+ if (
26
+ isinstance(value, Datetime)
27
+ or value.__class__.__name__ == Datetime.__name__
28
+ ):
29
+ return {
30
+ "__time__": [
31
+ value.year,
32
+ value.month,
33
+ value.day,
34
+ value.hour,
35
+ value.minute,
36
+ value.second,
37
+ value.microsecond,
38
+ ]
39
+ }
40
+ if (
41
+ isinstance(value, Timedelta)
42
+ or value.__class__.__name__ == Timedelta.__name__
43
+ ):
44
+ return {
45
+ "__delta__": [
46
+ value._timedelta.days,
47
+ value._timedelta.seconds,
48
+ ]
49
+ }
50
+ if isinstance(value, bytes):
51
+ return {"__bytes__": value.hex()}
52
+ if (
53
+ isinstance(value, decimal.Decimal)
54
+ or value.__class__.__name__ == decimal.Decimal.__name__
55
+ ):
56
+ return {"__fixed__": str(fix_precision(value))}
57
+ if (
58
+ isinstance(value, ContractingDecimal)
59
+ or value.__class__.__name__ == ContractingDecimal.__name__
60
+ ):
61
+ return {"__fixed__": str(fix_precision(value._d))}
62
+ return super().default(value)
63
+
64
+
65
+ def encode_int(value: int):
66
+ if MIN_INT < value < MAX_INT:
67
+ return value
68
+ return {"__big_int__": str(value)}
69
+
70
+
71
+ def encode_ints_in_dict(data: dict):
72
+ encoded = {}
73
+ for key, value in data.items():
74
+ if isinstance(value, int):
75
+ encoded[key] = encode_int(value)
76
+ elif isinstance(value, dict):
77
+ encoded[key] = encode_ints_in_dict(value)
78
+ elif isinstance(value, list):
79
+ encoded[key] = []
80
+ for item in value:
81
+ if isinstance(item, dict):
82
+ encoded[key].append(encode_ints_in_dict(item))
83
+ elif isinstance(item, int):
84
+ encoded[key].append(encode_int(item))
85
+ else:
86
+ encoded[key].append(item)
87
+ else:
88
+ encoded[key] = value
89
+ return encoded
90
+
91
+
92
+ def encode(data):
93
+ if isinstance(data, int):
94
+ data = encode_int(data)
95
+ elif isinstance(data, dict):
96
+ data = encode_ints_in_dict(data)
97
+ return json.dumps(data, cls=Encoder, separators=(",", ":"))
98
+
99
+
100
+ def as_object(value):
101
+ if "__time__" in value:
102
+ return Datetime(*value["__time__"])
103
+ if "__delta__" in value:
104
+ return Timedelta(
105
+ days=value["__delta__"][0], seconds=value["__delta__"][1]
106
+ )
107
+ if "__bytes__" in value:
108
+ return bytes.fromhex(value["__bytes__"])
109
+ if "__fixed__" in value:
110
+ return ContractingDecimal(value["__fixed__"])
111
+ if "__big_int__" in value:
112
+ return int(value["__big_int__"])
113
+ return dict(value)
114
+
115
+
116
+ def decode(data):
117
+ if data is None:
118
+ return None
119
+ if isinstance(data, bytes):
120
+ data = data.decode()
121
+ try:
122
+ return json.loads(data, object_hook=as_object)
123
+ except json.decoder.JSONDecodeError:
124
+ return None
125
+
126
+
127
+ def encode_kv(key, value):
128
+ return key.encode(), encode(value).encode()
129
+
130
+
131
+ def decode_kv(key, value):
132
+ return key.decode(), decode(value)
133
+
134
+
135
+ def convert(key, value):
136
+ if key == "__fixed__":
137
+ return ContractingDecimal(value)
138
+ if key == "__delta__":
139
+ return Timedelta(days=value[0], seconds=value[1])
140
+ if key == "__bytes__":
141
+ return bytes.fromhex(value)
142
+ if key == "__time__":
143
+ return Datetime(*value)
144
+ if key == "__big_int__":
145
+ return int(value)
146
+ return value
147
+
148
+
149
+ def convert_dict(data):
150
+ if not isinstance(data, dict):
151
+ return data
152
+
153
+ converted = {}
154
+ for key, value in data.items():
155
+ if key in TYPES:
156
+ return convert(key, value)
157
+ if isinstance(value, dict):
158
+ converted[key] = convert_dict(value)
159
+ elif isinstance(value, list):
160
+ converted[key] = [convert_dict(item) for item in value]
161
+ else:
162
+ converted[key] = value
163
+ return converted
@@ -0,0 +1,251 @@
1
+ from datetime import datetime as dt
2
+ from datetime import timedelta as td
3
+ from types import ModuleType
4
+
5
+ SECONDS_IN_MINUTE = 60
6
+ SECONDS_IN_HOUR = 3600
7
+ SECONDS_IN_DAY = 86400
8
+ SECONDS_IN_WEEK = 604800
9
+
10
+
11
+ def get_raw_seconds(weeks, days, hours, minutes, seconds):
12
+ m_sec = minutes * SECONDS_IN_MINUTE
13
+ h_sec = hours * SECONDS_IN_HOUR
14
+ d_sec = days * SECONDS_IN_DAY
15
+ w_sec = weeks * SECONDS_IN_WEEK
16
+ return seconds + m_sec + h_sec + d_sec + w_sec
17
+
18
+
19
+ def to_contract_time(py_dt):
20
+ if isinstance(py_dt, Datetime):
21
+ dt_obj = py_dt
22
+ elif isinstance(py_dt, dt):
23
+ dt_obj = py_dt
24
+ else:
25
+ raise TypeError("Expected datetime.datetime or Datetime")
26
+
27
+ return {
28
+ "__time__": [
29
+ dt_obj.year,
30
+ dt_obj.month,
31
+ dt_obj.day,
32
+ dt_obj.hour,
33
+ dt_obj.minute,
34
+ dt_obj.second,
35
+ ]
36
+ }
37
+
38
+
39
+ class Datetime:
40
+ def __init__(
41
+ self, year, month, day, hour=0, minute=0, second=0, microsecond=0
42
+ ):
43
+ self._datetime = dt(
44
+ year=year,
45
+ month=month,
46
+ day=day,
47
+ hour=hour,
48
+ minute=minute,
49
+ second=second,
50
+ microsecond=microsecond,
51
+ )
52
+ self.year = self._datetime.year
53
+ self.month = self._datetime.month
54
+ self.day = self._datetime.day
55
+ self.hour = self._datetime.hour
56
+ self.minute = self._datetime.minute
57
+ self.second = self._datetime.second
58
+ self.microsecond = self._datetime.microsecond
59
+
60
+ def __lt__(self, other):
61
+ if not isinstance(other, Datetime):
62
+ raise TypeError(f"{type(other)} is not a Datetime!")
63
+ return self._datetime < other._datetime
64
+
65
+ def __le__(self, other):
66
+ if not isinstance(other, Datetime):
67
+ raise TypeError(f"{type(other)} is not a Datetime!")
68
+ return self._datetime <= other._datetime
69
+
70
+ def __eq__(self, other):
71
+ if not isinstance(other, Datetime):
72
+ raise TypeError(f"{type(other)} is not a Datetime!")
73
+ return self._datetime == other._datetime
74
+
75
+ def __ge__(self, other):
76
+ if not isinstance(other, Datetime):
77
+ raise TypeError(f"{type(other)} is not a Datetime!")
78
+ return self._datetime >= other._datetime
79
+
80
+ def __gt__(self, other):
81
+ if not isinstance(other, Datetime):
82
+ raise TypeError(f"{type(other)} is not a Datetime!")
83
+ return self._datetime > other._datetime
84
+
85
+ def __ne__(self, other):
86
+ if not isinstance(other, Datetime):
87
+ raise TypeError(f"{type(other)} is not a Datetime!")
88
+ return self._datetime != other._datetime
89
+
90
+ def __sub__(self, other):
91
+ if isinstance(other, Datetime):
92
+ delta = self._datetime - other._datetime
93
+ return Timedelta(days=delta.days, seconds=delta.seconds)
94
+ return NotImplemented
95
+
96
+ def __add__(self, other):
97
+ if isinstance(other, Timedelta):
98
+ return Datetime._from_datetime(self._datetime + other._timedelta)
99
+ return NotImplemented
100
+
101
+ def __str__(self):
102
+ return str(self._datetime)
103
+
104
+ def __repr__(self):
105
+ return self.__str__()
106
+
107
+ @classmethod
108
+ def _from_datetime(cls, value: dt):
109
+ return cls(
110
+ year=value.year,
111
+ month=value.month,
112
+ day=value.day,
113
+ hour=value.hour,
114
+ minute=value.minute,
115
+ second=value.second,
116
+ microsecond=value.microsecond,
117
+ )
118
+
119
+ @classmethod
120
+ def strptime(cls, date_string, format):
121
+ return cls._from_datetime(dt.strptime(date_string, format))
122
+
123
+
124
+ class Timedelta:
125
+ def __init__(self, weeks=0, days=0, hours=0, minutes=0, seconds=0):
126
+ self._timedelta = td(
127
+ weeks=int(weeks),
128
+ days=int(days),
129
+ hours=int(hours),
130
+ minutes=int(minutes),
131
+ seconds=int(seconds),
132
+ )
133
+ self.__raw_seconds = get_raw_seconds(
134
+ weeks=int(weeks),
135
+ days=int(days),
136
+ hours=int(hours),
137
+ minutes=int(minutes),
138
+ seconds=int(seconds),
139
+ )
140
+
141
+ def __lt__(self, other):
142
+ if not isinstance(other, Timedelta):
143
+ raise TypeError(f"{type(other)} is not a Timedelta!")
144
+ return self._timedelta < other._timedelta
145
+
146
+ def __le__(self, other):
147
+ if not isinstance(other, Timedelta):
148
+ raise TypeError(f"{type(other)} is not a Timedelta!")
149
+ return self._timedelta <= other._timedelta
150
+
151
+ def __eq__(self, other):
152
+ if not isinstance(other, Timedelta):
153
+ raise TypeError(f"{type(other)} is not a Timedelta!")
154
+ return self._timedelta == other._timedelta
155
+
156
+ def __ge__(self, other):
157
+ if not isinstance(other, Timedelta):
158
+ raise TypeError(f"{type(other)} is not a Timedelta!")
159
+ return self._timedelta >= other._timedelta
160
+
161
+ def __gt__(self, other):
162
+ if not isinstance(other, Timedelta):
163
+ raise TypeError(f"{type(other)} is not a Timedelta!")
164
+ return self._timedelta > other._timedelta
165
+
166
+ def __ne__(self, other):
167
+ if not isinstance(other, Timedelta):
168
+ raise TypeError(f"{type(other)} is not a Timedelta!")
169
+ return self._timedelta != other._timedelta
170
+
171
+ def __add__(self, other):
172
+ if isinstance(other, Timedelta):
173
+ return Timedelta(
174
+ days=self._timedelta.days + other._timedelta.days,
175
+ seconds=self._timedelta.seconds + other._timedelta.seconds,
176
+ )
177
+
178
+ if isinstance(other, Datetime):
179
+ return Datetime._from_datetime(other._datetime + self._timedelta)
180
+
181
+ return NotImplemented
182
+
183
+ def __sub__(self, other):
184
+ if isinstance(other, Timedelta):
185
+ return Timedelta(
186
+ days=self._timedelta.days - other._timedelta.days,
187
+ seconds=self._timedelta.seconds - other._timedelta.seconds,
188
+ )
189
+
190
+ if isinstance(other, Datetime):
191
+ return Datetime._from_datetime(other._datetime - self._timedelta)
192
+
193
+ return NotImplemented
194
+
195
+ def __mul__(self, other):
196
+ if isinstance(other, Timedelta):
197
+ return Timedelta(
198
+ days=self._timedelta.days * other._timedelta.days,
199
+ seconds=self._timedelta.seconds * other._timedelta.seconds,
200
+ )
201
+ if isinstance(other, int):
202
+ return Timedelta(
203
+ days=self._timedelta.days * other,
204
+ seconds=self._timedelta.seconds * other,
205
+ )
206
+
207
+ return NotImplemented
208
+
209
+ def __str__(self):
210
+ return str(self._timedelta)
211
+
212
+ def __repr__(self):
213
+ return self.__str__()
214
+
215
+ @property
216
+ def seconds(self):
217
+ return self.__raw_seconds
218
+
219
+ @property
220
+ def minutes(self):
221
+ return self.__raw_seconds // SECONDS_IN_MINUTE
222
+
223
+ @property
224
+ def hours(self):
225
+ return self.__raw_seconds // SECONDS_IN_HOUR
226
+
227
+ @property
228
+ def days(self):
229
+ return self.__raw_seconds // SECONDS_IN_DAY
230
+
231
+ @property
232
+ def weeks(self):
233
+ return self.__raw_seconds // SECONDS_IN_WEEK
234
+
235
+
236
+ WEEKS = Timedelta(weeks=1)
237
+ DAYS = Timedelta(days=1)
238
+ HOURS = Timedelta(hours=1)
239
+ MINUTES = Timedelta(minutes=1)
240
+ SECONDS = Timedelta(seconds=1)
241
+
242
+ datetime_module = ModuleType("datetime")
243
+ datetime_module.datetime = Datetime
244
+ datetime_module.timedelta = Timedelta
245
+ datetime_module.WEEKS = WEEKS
246
+ datetime_module.DAYS = DAYS
247
+ datetime_module.HOURS = HOURS
248
+ datetime_module.MINUTES = MINUTES
249
+ datetime_module.SECONDS = SECONDS
250
+
251
+ exports = {"datetime": datetime_module}
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: xian-tech-runtime-types
3
+ Version: 0.1.0
4
+ Summary: Shared deterministic runtime types for the Xian stack
5
+ Author-email: Xian Network <info@xian.org>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+
10
+ # xian-tech-runtime-types
11
+
12
+ Shared deterministic runtime types for the Xian stack.
@@ -0,0 +1,10 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/xian_runtime_types/__init__.py
4
+ src/xian_runtime_types/decimal.py
5
+ src/xian_runtime_types/encoding.py
6
+ src/xian_runtime_types/time.py
7
+ src/xian_tech_runtime_types.egg-info/PKG-INFO
8
+ src/xian_tech_runtime_types.egg-info/SOURCES.txt
9
+ src/xian_tech_runtime_types.egg-info/dependency_links.txt
10
+ src/xian_tech_runtime_types.egg-info/top_level.txt