meshtrade 1.22.0__py3-none-any.whl → 1.23.1__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.

Potentially problematic release.


This version of meshtrade might be problematic. Click here for more details.

Files changed (29) hide show
  1. meshtrade/compliance/client/v1/__init__.py +12 -0
  2. meshtrade/compliance/client/v1/client_roles.py +123 -0
  3. meshtrade/compliance/client/v1/service_meshpy.py +1 -0
  4. meshtrade/iam/api_user/v1/__init__.py +6 -0
  5. meshtrade/iam/api_user/v1/api_user_state_machine.py +104 -0
  6. meshtrade/iam/api_user/v1/service_meshpy.py +1 -0
  7. meshtrade/iam/group/v1/service_meshpy.py +1 -0
  8. meshtrade/iam/role/v1/__init__.py +16 -2
  9. meshtrade/iam/role/v1/role.py +162 -11
  10. meshtrade/iam/user/v1/service_meshpy.py +1 -0
  11. meshtrade/ledger/transaction/v1/__init__.py +4 -0
  12. meshtrade/ledger/transaction/v1/service_meshpy.py +2 -1
  13. meshtrade/ledger/transaction/v1/transaction_state_machine.py +75 -0
  14. meshtrade/reporting/account_report/v1/__init__.py +4 -0
  15. meshtrade/reporting/account_report/v1/income_entry.py +35 -0
  16. meshtrade/reporting/account_report/v1/service_meshpy.py +1 -0
  17. meshtrade/trading/limit_order/v1/service_meshpy.py +1 -0
  18. meshtrade/trading/market_order/v1/service_meshpy.py +1 -0
  19. meshtrade/type/v1/__init__.py +81 -11
  20. meshtrade/type/v1/amount.py +429 -5
  21. meshtrade/type/v1/decimal_built_in_conversions.py +8 -3
  22. meshtrade/type/v1/decimal_operations.py +354 -0
  23. meshtrade/type/v1/ledger.py +76 -1
  24. meshtrade/type/v1/token.py +144 -0
  25. meshtrade/wallet/account/v1/service_meshpy.py +1 -0
  26. {meshtrade-1.22.0.dist-info → meshtrade-1.23.1.dist-info}/METADATA +1 -1
  27. {meshtrade-1.22.0.dist-info → meshtrade-1.23.1.dist-info}/RECORD +29 -23
  28. {meshtrade-1.22.0.dist-info → meshtrade-1.23.1.dist-info}/WHEEL +0 -0
  29. {meshtrade-1.22.0.dist-info → meshtrade-1.23.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,354 @@
1
+ """Decimal operations utility functions for Mesh API.
2
+
3
+ This module provides arithmetic, comparison, and utility functions for working
4
+ with protobuf Decimal messages, offering a Pythonic API for decimal arithmetic
5
+ with consistent precision handling.
6
+ """
7
+
8
+ from decimal import ROUND_HALF_UP
9
+
10
+ from .decimal_built_in_conversions import decimal_to_built_in
11
+ from .decimal_pb2 import Decimal
12
+
13
+
14
+ def decimal_add(d1: Decimal | None, d2: Decimal | None) -> Decimal:
15
+ """Add two Decimal values.
16
+
17
+ Args:
18
+ d1: First decimal value (None treated as 0)
19
+ d2: Second decimal value (None treated as 0)
20
+
21
+ Returns:
22
+ New Decimal containing the sum (d1 + d2)
23
+
24
+ None Safety:
25
+ None inputs are treated as zero
26
+
27
+ Example:
28
+ >>> d1 = Decimal(value="10.5")
29
+ >>> d2 = Decimal(value="20.3")
30
+ >>> result = decimal_add(d1, d2)
31
+ >>> result.value
32
+ '30.8'
33
+ """
34
+ val1 = decimal_to_built_in(d1)
35
+ val2 = decimal_to_built_in(d2)
36
+ return Decimal(value=str(val1 + val2))
37
+
38
+
39
+ def decimal_sub(d1: Decimal | None, d2: Decimal | None) -> Decimal:
40
+ """Subtract two Decimal values.
41
+
42
+ Args:
43
+ d1: First decimal value (None treated as 0)
44
+ d2: Second decimal value (subtrahend, None treated as 0)
45
+
46
+ Returns:
47
+ New Decimal containing the difference (d1 - d2)
48
+
49
+ None Safety:
50
+ None inputs are treated as zero
51
+
52
+ Example:
53
+ >>> d1 = Decimal(value="100.5")
54
+ >>> d2 = Decimal(value="30.2")
55
+ >>> result = decimal_sub(d1, d2)
56
+ >>> result.value
57
+ '70.3'
58
+ """
59
+ val1 = decimal_to_built_in(d1)
60
+ val2 = decimal_to_built_in(d2)
61
+ return Decimal(value=str(val1 - val2))
62
+
63
+
64
+ def decimal_mul(d1: Decimal | None, d2: Decimal | None) -> Decimal:
65
+ """Multiply two Decimal values.
66
+
67
+ Args:
68
+ d1: First decimal value (None treated as 0)
69
+ d2: Second decimal value (None treated as 0)
70
+
71
+ Returns:
72
+ New Decimal containing the product (d1 * d2)
73
+
74
+ None Safety:
75
+ None inputs are treated as zero
76
+
77
+ Example:
78
+ >>> d1 = Decimal(value="10.5")
79
+ >>> d2 = Decimal(value="2")
80
+ >>> result = decimal_mul(d1, d2)
81
+ >>> result.value
82
+ '21.0'
83
+ """
84
+ val1 = decimal_to_built_in(d1)
85
+ val2 = decimal_to_built_in(d2)
86
+ return Decimal(value=str(val1 * val2))
87
+
88
+
89
+ def decimal_div(d1: Decimal | None, d2: Decimal | None) -> Decimal:
90
+ """Divide two Decimal values.
91
+
92
+ Args:
93
+ d1: Dividend (None treated as 0)
94
+ d2: Divisor (must not be zero, None treated as 0)
95
+
96
+ Returns:
97
+ New Decimal containing the quotient (d1 / d2)
98
+
99
+ Raises:
100
+ ZeroDivisionError: If d2 is zero
101
+
102
+ None Safety:
103
+ None inputs are treated as zero (note: None d2 will raise ZeroDivisionError)
104
+
105
+ Example:
106
+ >>> d1 = Decimal(value="100")
107
+ >>> d2 = Decimal(value="4")
108
+ >>> result = decimal_div(d1, d2)
109
+ >>> result.value
110
+ '25'
111
+ """
112
+ val1 = decimal_to_built_in(d1)
113
+ val2 = decimal_to_built_in(d2)
114
+
115
+ if val2 == 0:
116
+ raise ZeroDivisionError("cannot divide by zero")
117
+
118
+ return Decimal(value=str(val1 / val2))
119
+
120
+
121
+ def decimal_equal(d1: Decimal | None, d2: Decimal | None) -> bool:
122
+ """Check if two Decimal values are equal.
123
+
124
+ Args:
125
+ d1: First decimal value (None treated as 0)
126
+ d2: Second decimal value (None treated as 0)
127
+
128
+ Returns:
129
+ True if d1 == d2, False otherwise
130
+
131
+ None Safety:
132
+ None inputs are treated as zero
133
+
134
+ Example:
135
+ >>> d1 = Decimal(value="10.5")
136
+ >>> d2 = Decimal(value="10.5")
137
+ >>> decimal_equal(d1, d2)
138
+ True
139
+ """
140
+ val1 = decimal_to_built_in(d1)
141
+ val2 = decimal_to_built_in(d2)
142
+ return val1 == val2
143
+
144
+
145
+ def decimal_less_than(d1: Decimal | None, d2: Decimal | None) -> bool:
146
+ """Check if first Decimal is less than second.
147
+
148
+ Args:
149
+ d1: First decimal value (None treated as 0)
150
+ d2: Second decimal value (None treated as 0)
151
+
152
+ Returns:
153
+ True if d1 < d2, False otherwise
154
+
155
+ None Safety:
156
+ None inputs are treated as zero
157
+
158
+ Example:
159
+ >>> d1 = Decimal(value="10.5")
160
+ >>> d2 = Decimal(value="20.3")
161
+ >>> decimal_less_than(d1, d2)
162
+ True
163
+ """
164
+ val1 = decimal_to_built_in(d1)
165
+ val2 = decimal_to_built_in(d2)
166
+ return val1 < val2
167
+
168
+
169
+ def decimal_less_than_or_equal(d1: Decimal | None, d2: Decimal | None) -> bool:
170
+ """Check if first Decimal is less than or equal to second.
171
+
172
+ Args:
173
+ d1: First decimal value (None treated as 0)
174
+ d2: Second decimal value (None treated as 0)
175
+
176
+ Returns:
177
+ True if d1 <= d2, False otherwise
178
+
179
+ None Safety:
180
+ None inputs are treated as zero
181
+
182
+ Example:
183
+ >>> d1 = Decimal(value="10.5")
184
+ >>> d2 = Decimal(value="10.5")
185
+ >>> decimal_less_than_or_equal(d1, d2)
186
+ True
187
+ """
188
+ val1 = decimal_to_built_in(d1)
189
+ val2 = decimal_to_built_in(d2)
190
+ return val1 <= val2
191
+
192
+
193
+ def decimal_greater_than(d1: Decimal | None, d2: Decimal | None) -> bool:
194
+ """Check if first Decimal is greater than second.
195
+
196
+ Args:
197
+ d1: First decimal value (None treated as 0)
198
+ d2: Second decimal value (None treated as 0)
199
+
200
+ Returns:
201
+ True if d1 > d2, False otherwise
202
+
203
+ None Safety:
204
+ None inputs are treated as zero
205
+
206
+ Example:
207
+ >>> d1 = Decimal(value="20.3")
208
+ >>> d2 = Decimal(value="10.5")
209
+ >>> decimal_greater_than(d1, d2)
210
+ True
211
+ """
212
+ val1 = decimal_to_built_in(d1)
213
+ val2 = decimal_to_built_in(d2)
214
+ return val1 > val2
215
+
216
+
217
+ def decimal_greater_than_or_equal(d1: Decimal | None, d2: Decimal | None) -> bool:
218
+ """Check if first Decimal is greater than or equal to second.
219
+
220
+ Args:
221
+ d1: First decimal value (None treated as 0)
222
+ d2: Second decimal value (None treated as 0)
223
+
224
+ Returns:
225
+ True if d1 >= d2, False otherwise
226
+
227
+ None Safety:
228
+ None inputs are treated as zero
229
+
230
+ Example:
231
+ >>> d1 = Decimal(value="10.5")
232
+ >>> d2 = Decimal(value="10.5")
233
+ >>> decimal_greater_than_or_equal(d1, d2)
234
+ True
235
+ """
236
+ val1 = decimal_to_built_in(d1)
237
+ val2 = decimal_to_built_in(d2)
238
+ return val1 >= val2
239
+
240
+
241
+ def decimal_is_zero(d: Decimal | None) -> bool:
242
+ """Check if Decimal value is zero.
243
+
244
+ Args:
245
+ d: Decimal value to check (None treated as 0)
246
+
247
+ Returns:
248
+ True if d == 0, False otherwise
249
+
250
+ None Safety:
251
+ None inputs are treated as zero (returns True)
252
+
253
+ Example:
254
+ >>> d = Decimal(value="0")
255
+ >>> decimal_is_zero(d)
256
+ True
257
+ >>> d2 = Decimal(value="0.001")
258
+ >>> decimal_is_zero(d2)
259
+ False
260
+ """
261
+ val = decimal_to_built_in(d)
262
+ return val == 0
263
+
264
+
265
+ def decimal_is_negative(d: Decimal | None) -> bool:
266
+ """Check if Decimal value is negative (< 0).
267
+
268
+ Args:
269
+ d: Decimal value to check (None treated as 0)
270
+
271
+ Returns:
272
+ True if d < 0, False if d >= 0
273
+
274
+ None Safety:
275
+ None inputs are treated as zero (returns False)
276
+
277
+ Example:
278
+ >>> d = Decimal(value="-10.5")
279
+ >>> decimal_is_negative(d)
280
+ True
281
+ >>> d2 = Decimal(value="10.5")
282
+ >>> decimal_is_negative(d2)
283
+ False
284
+ """
285
+ val = decimal_to_built_in(d)
286
+ return val < 0
287
+
288
+
289
+ def decimal_is_positive(d: Decimal | None) -> bool:
290
+ """Check if Decimal value is positive (> 0).
291
+
292
+ Args:
293
+ d: Decimal value to check (None treated as 0)
294
+
295
+ Returns:
296
+ True if d > 0, False if d <= 0
297
+
298
+ None Safety:
299
+ None inputs are treated as zero (returns False)
300
+
301
+ Example:
302
+ >>> d = Decimal(value="10.5")
303
+ >>> decimal_is_positive(d)
304
+ True
305
+ >>> d2 = Decimal(value="0")
306
+ >>> decimal_is_positive(d2)
307
+ False
308
+ """
309
+ val = decimal_to_built_in(d)
310
+ return val > 0
311
+
312
+
313
+ def decimal_round(d: Decimal | None, places: int) -> Decimal:
314
+ """Round Decimal to specified number of decimal places.
315
+
316
+ If places < 0, it rounds the integer part to the nearest 10^(-places).
317
+
318
+ Args:
319
+ d: Decimal value to round (None treated as 0)
320
+ places: Number of decimal places (can be negative)
321
+
322
+ Returns:
323
+ New Decimal containing the rounded value
324
+
325
+ None Safety:
326
+ None inputs are treated as zero
327
+
328
+ Example:
329
+ >>> d = Decimal(value="5.45")
330
+ >>> result = decimal_round(d, 1)
331
+ >>> result.value
332
+ '5.5'
333
+ >>> d2 = Decimal(value="545")
334
+ >>> result2 = decimal_round(d2, -1)
335
+ >>> result2.value
336
+ '550'
337
+ """
338
+ from decimal import Decimal as PyDecimal
339
+
340
+ val = decimal_to_built_in(d)
341
+
342
+ if places < 0:
343
+ # For negative places, use shift-quantize-shift back approach
344
+ # to properly round the integer part
345
+ scale = PyDecimal(10) ** (-places)
346
+ shifted = val / scale
347
+ rounded_shifted = shifted.quantize(PyDecimal("1"), rounding=ROUND_HALF_UP)
348
+ rounded_val = rounded_shifted * scale
349
+ else:
350
+ # For positive places, quantize directly
351
+ quantizer = PyDecimal(10) ** -places
352
+ rounded_val = val.quantize(quantizer, rounding=ROUND_HALF_UP)
353
+
354
+ return Decimal(value=str(rounded_val))
@@ -10,7 +10,7 @@ class UnsupportedLedgerError(Exception):
10
10
  """Exception raised for unsupported Ledger values."""
11
11
 
12
12
  def __init__(self, ledger: Ledger):
13
- self.financial_business_day_convention = ledger
13
+ self.ledger = ledger
14
14
  message = f"Unsupported Ledger: {ledger}"
15
15
  super().__init__(message)
16
16
 
@@ -23,3 +23,78 @@ def get_ledger_no_decimal_places(ledger: Ledger) -> int:
23
23
  return _ledger_decimal_places[ledger]
24
24
  else:
25
25
  raise UnsupportedLedgerError(ledger)
26
+
27
+
28
+ def ledger_to_pretty_string(ledger: Ledger) -> str:
29
+ """Convert the Ledger enum value to a human-readable network name.
30
+
31
+ This method provides user-friendly names for each blockchain network/ledger type.
32
+
33
+ Args:
34
+ ledger: The Ledger enum value
35
+
36
+ Returns:
37
+ A human-readable network name string, or "Unknown" for invalid/unrecognized values
38
+
39
+ Example:
40
+ >>> ledger_to_pretty_string(Ledger.LEDGER_STELLAR)
41
+ 'Stellar'
42
+ >>> ledger_to_pretty_string(Ledger.LEDGER_ETHEREUM)
43
+ 'Ethereum'
44
+ >>> ledger_to_pretty_string(Ledger.LEDGER_UNSPECIFIED)
45
+ 'Unspecified'
46
+ """
47
+ if ledger == Ledger.LEDGER_STELLAR:
48
+ return "Stellar"
49
+ elif ledger == Ledger.LEDGER_ETHEREUM:
50
+ return "Ethereum"
51
+ elif ledger == Ledger.LEDGER_BITCOIN:
52
+ return "Bitcoin"
53
+ elif ledger == Ledger.LEDGER_LITECOIN:
54
+ return "Litecoin"
55
+ elif ledger == Ledger.LEDGER_XRP:
56
+ return "XRP"
57
+ elif ledger == Ledger.LEDGER_SA_STOCK_BROKERS:
58
+ return "SA Stock Brokers"
59
+ elif ledger == Ledger.LEDGER_NULL:
60
+ return "Null"
61
+ elif ledger == Ledger.LEDGER_UNSPECIFIED:
62
+ return "Unspecified"
63
+ else:
64
+ return "Unknown"
65
+
66
+
67
+ def ledger_is_valid(ledger: Ledger) -> bool:
68
+ """Check if ledger value is valid (within enum range).
69
+
70
+ Args:
71
+ ledger: The Ledger enum value to check
72
+
73
+ Returns:
74
+ True if the ledger is a valid enum value, False otherwise
75
+
76
+ Example:
77
+ >>> ledger_is_valid(Ledger.LEDGER_STELLAR)
78
+ True
79
+ >>> ledger_is_valid(999) # Invalid enum value
80
+ False
81
+ """
82
+ return ledger in Ledger.values()
83
+
84
+
85
+ def ledger_is_valid_and_defined(ledger: Ledger) -> bool:
86
+ """Check if ledger is valid and not UNSPECIFIED.
87
+
88
+ Args:
89
+ ledger: The Ledger enum value to check
90
+
91
+ Returns:
92
+ True if the ledger is valid and not LEDGER_UNSPECIFIED, False otherwise
93
+
94
+ Example:
95
+ >>> ledger_is_valid_and_defined(Ledger.LEDGER_STELLAR)
96
+ True
97
+ >>> ledger_is_valid_and_defined(Ledger.LEDGER_UNSPECIFIED)
98
+ False
99
+ """
100
+ return ledger_is_valid(ledger) and ledger != Ledger.LEDGER_UNSPECIFIED
@@ -0,0 +1,144 @@
1
+ """Token utility functions for Mesh API.
2
+
3
+ This module provides utility functions for working with Token protobuf messages,
4
+ including helper functions for token creation, validation, and formatting.
5
+ """
6
+
7
+ from .ledger_pb2 import Ledger
8
+ from .token_pb2 import Token
9
+
10
+
11
+ def new_undefined_token() -> Token:
12
+ """Create a new Token representing an undefined or placeholder token.
13
+
14
+ The undefined token has:
15
+ - Code: "-"
16
+ - Issuer: "-"
17
+ - Ledger: LEDGER_UNSPECIFIED
18
+
19
+ This is useful as a sentinel value to represent the absence of a valid token
20
+ or as a placeholder in data structures.
21
+
22
+ Returns:
23
+ A Token configured as undefined
24
+
25
+ Example:
26
+ >>> token = new_undefined_token()
27
+ >>> token.code
28
+ '-'
29
+ >>> token.issuer
30
+ '-'
31
+ >>> token_is_undefined(token)
32
+ True
33
+ """
34
+ return Token(
35
+ code="-",
36
+ issuer="-",
37
+ ledger=Ledger.LEDGER_UNSPECIFIED,
38
+ )
39
+
40
+
41
+ def token_is_undefined(token: Token | None) -> bool:
42
+ """Check whether this token represents an undefined or placeholder token.
43
+
44
+ A token is considered undefined if:
45
+ - The token is None, OR
46
+ - The token has Code == "-" AND Issuer == "-" AND Ledger == LEDGER_UNSPECIFIED
47
+
48
+ Args:
49
+ token: Token to check (can be None)
50
+
51
+ Returns:
52
+ True if the token is undefined (None or matches undefined pattern), False otherwise
53
+
54
+ None Safety:
55
+ Returns True if token is None
56
+
57
+ Example:
58
+ >>> token = None
59
+ >>> token_is_undefined(token)
60
+ True
61
+ >>> token = new_undefined_token()
62
+ >>> token_is_undefined(token)
63
+ True
64
+ >>> defined = Token(code="USD", issuer="ISSUER", ledger=Ledger.LEDGER_STELLAR)
65
+ >>> token_is_undefined(defined)
66
+ False
67
+ """
68
+ if token is None:
69
+ return True
70
+
71
+ return token.code == "-" and token.issuer == "-" and token.ledger == Ledger.LEDGER_UNSPECIFIED
72
+
73
+
74
+ def token_is_equal_to(token1: Token | None, token2: Token | None) -> bool:
75
+ """Compare two tokens for equality.
76
+
77
+ Two tokens are considered equal if and only if all of the following match:
78
+ - Code (asset code)
79
+ - Issuer (asset issuer)
80
+ - Ledger (blockchain/ledger type)
81
+
82
+ Args:
83
+ token1: First token to compare (can be None)
84
+ token2: Second token to compare (can be None)
85
+
86
+ Returns:
87
+ True if both tokens are equal (including both being None), False otherwise
88
+
89
+ None Safety:
90
+ Returns True if both are None, False if only one is None
91
+
92
+ Example:
93
+ >>> token1 = Token(code="USD", issuer="ISSUER1", ledger=Ledger.LEDGER_STELLAR)
94
+ >>> token2 = Token(code="USD", issuer="ISSUER1", ledger=Ledger.LEDGER_STELLAR)
95
+ >>> token_is_equal_to(token1, token2)
96
+ True
97
+ >>> token3 = Token(code="EUR", issuer="ISSUER1", ledger=Ledger.LEDGER_STELLAR)
98
+ >>> token_is_equal_to(token1, token3)
99
+ False
100
+ >>> token_is_equal_to(None, None)
101
+ True
102
+ """
103
+ # Handle None cases
104
+ if token1 is None and token2 is None:
105
+ return True
106
+ if token1 is None or token2 is None:
107
+ return False
108
+
109
+ return token1.code == token2.code and token1.issuer == token2.issuer and token1.ledger == token2.ledger
110
+
111
+
112
+ def token_pretty_string(token: Token | None) -> str:
113
+ """Return a human-readable string representation of the token.
114
+
115
+ Format: "CODE by ISSUER on NETWORK"
116
+
117
+ Args:
118
+ token: Token to format (can be None)
119
+
120
+ Returns:
121
+ A formatted string describing the token, or "undefined" if None/undefined
122
+
123
+ None Safety:
124
+ Returns "undefined" if token is None
125
+
126
+ Example:
127
+ >>> token = Token(code="USD", issuer="CIRCLE", ledger=Ledger.LEDGER_STELLAR)
128
+ >>> token_pretty_string(token)
129
+ 'USD by CIRCLE on Stellar'
130
+ >>> token_pretty_string(None)
131
+ 'undefined'
132
+ >>> token_pretty_string(new_undefined_token())
133
+ 'undefined'
134
+ """
135
+ if token is None:
136
+ return "undefined"
137
+
138
+ if token_is_undefined(token):
139
+ return "undefined"
140
+
141
+ # Import ledger utility for pretty printing
142
+ from .ledger import ledger_to_pretty_string
143
+
144
+ return f"{token.code} by {token.issuer} on {ledger_to_pretty_string(token.ledger)}"
@@ -9,6 +9,7 @@ the service interface with resource management capabilities, providing authentic
9
9
  timeouts, and proper connection handling.
10
10
  """
11
11
 
12
+ from collections.abc import Iterator
12
13
  from datetime import timedelta
13
14
  from typing import Optional
14
15
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshtrade
3
- Version: 1.22.0
3
+ Version: 1.23.1
4
4
  Summary: Integration SDK for Mesh API Services
5
5
  Author-email: Bernard Bussy <bernard@meshtrade.co>
6
6
  License: LicenseRef-My-Custom-License