mpt-extension-sdk 5.2.2__py3-none-any.whl → 5.2.4__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.
@@ -1,5 +1,4 @@
1
1
  import logging
2
- from datetime import date
3
2
  from functools import cache
4
3
  from itertools import batched
5
4
 
@@ -191,21 +190,6 @@ def get_subscriptions_by_query(
191
190
  return _paginated(mpt_client, url, limit=limit)
192
191
 
193
192
 
194
- def get_agreements_by_next_sync(mpt_client, next_sync_parameter):
195
- today = date.today().isoformat()
196
- param_condition = (
197
- f"any(parameters.fulfillment,and(eq(externalId,{next_sync_parameter})"
198
- f",lt(displayValue,{today})))"
199
- )
200
- status_condition = "eq(status,Active)"
201
-
202
- rql_query = (
203
- f"and({status_condition},{param_condition})"
204
- "&select=lines,parameters,subscriptions,product,listing"
205
- )
206
- return get_agreements_by_query(mpt_client, rql_query)
207
-
208
-
209
193
  @wrap_mpt_http_error
210
194
  def update_agreement_subscription(mpt_client, subscription_id, **kwargs):
211
195
  response = mpt_client.put(
@@ -146,7 +146,7 @@ LOGGING = {
146
146
  "disable_existing_loggers": False,
147
147
  "formatters": {
148
148
  "verbose": {
149
- "format": "{asctime} {name} {levelname} (pid: {process}) {message}",
149
+ "format": "{asctime} {name} {levelname} (pid: {process}, thread: {thread}) {message}",
150
150
  "style": "{",
151
151
  },
152
152
  "rich": {
@@ -154,7 +154,7 @@ LOGGING = {
154
154
  "style": "{",
155
155
  },
156
156
  "opentelemetry": {
157
- "format": "(pid: {process}) {message}",
157
+ "format": "(pid: {process}, thread: {thread}) {message}",
158
158
  "style": "{",
159
159
  },
160
160
  },
@@ -208,6 +208,7 @@ MPT_API_TOKEN = os.getenv("MPT_API_TOKEN", "change-me!")
208
208
  MPT_API_TOKEN_OPERATIONS = os.getenv("MPT_API_TOKEN_OPERATIONS", "change-me!")
209
209
  MPT_PRODUCTS_IDS = os.getenv("MPT_PRODUCTS_IDS", "PRD-1111-1111")
210
210
  MPT_PORTAL_BASE_URL = os.getenv("MPT_PORTAL_BASE_URL", "https://portal.s1.show")
211
+ MPT_KEY_VAULT_NAME = os.getenv("MPT_KEY_VAULT_NAME", "mpt-key-vault")
211
212
 
212
213
  MPT_ORDERS_API_POLLING_INTERVAL_SECS = int(
213
214
  os.getenv("MPT_ORDERS_API_POLLING_INTERVAL_SECS", "120")
@@ -217,3 +218,8 @@ EXTENSION_CONFIG = {
217
218
  "DUE_DATE_DAYS": "30",
218
219
  "ORDER_CREATION_WINDOW_HOURS": os.getenv("EXT_ORDER_CREATION_WINDOW_HOURS", "24"),
219
220
  }
221
+
222
+ MPT_SETUP_CONTEXTS_FUNC = os.getenv(
223
+ "MPT_SETUP_CONTEXTS_FUNC",
224
+ "mpt_extension_sdk.runtime.events.utils.setup_contexts",
225
+ )
@@ -1,4 +1,3 @@
1
-
2
1
  from mpt_extension_sdk.constants import (
3
2
  DEFAULT_APP_CONFIG_GROUP,
4
3
  DEFAULT_APP_CONFIG_NAME,
@@ -9,6 +9,7 @@ from django.conf import settings
9
9
 
10
10
  from mpt_extension_sdk.core.events.dataclasses import Event
11
11
  from mpt_extension_sdk.core.utils import setup_client
12
+ from mpt_extension_sdk.swo_rql import RQLQuery
12
13
 
13
14
  logger = logging.getLogger(__name__)
14
15
 
@@ -73,12 +74,13 @@ class OrderEventProducer(EventProducer):
73
74
  )
74
75
 
75
76
  def get_processing_orders(self):
76
- products = ",".join(settings.MPT_PRODUCTS_IDS)
77
77
  orders = []
78
- rql_query = f"and(in(agreement.product.id,({products})),eq(status,processing))"
78
+ rql_query = RQLQuery().agreement.product.id.in_(
79
+ settings.MPT_PRODUCTS_IDS
80
+ ) and RQLQuery(status="processing")
79
81
  url = (
80
82
  f"/commerce/orders?{rql_query}&select=audit,parameters,lines,subscriptions,"
81
- f"subscriptions.lines,agreement,buyer&order=audit.created.at"
83
+ f"subscriptions.lines,agreement,buyer,seller&order=audit.created.at"
82
84
  )
83
85
  page = None
84
86
  limit = 10
@@ -0,0 +1,5 @@
1
+ from mpt_extension_sdk.swo_rql.query_builder import RQLQuery
2
+
3
+ R = RQLQuery
4
+
5
+ __all__ = ["R", "RQLQuery"]
@@ -0,0 +1,7 @@
1
+ COMP = ("eq", "ne", "lt", "le", "gt", "ge")
2
+ SEARCH = ("like", "ilike")
3
+ LIST = ("in", "out")
4
+ NULL = "null"
5
+ EMPTY = "empty"
6
+
7
+ KEYWORDS = (*COMP, *SEARCH, *LIST, NULL, EMPTY)
@@ -0,0 +1,392 @@
1
+ from mpt_extension_sdk.swo_rql import constants
2
+
3
+
4
+ def parse_kwargs(query_dict):
5
+ query = []
6
+ for lookup, value in query_dict.items():
7
+ tokens = lookup.split("__")
8
+ if len(tokens) == 1:
9
+ # field=value
10
+ field = tokens[0]
11
+ value = rql_encode("eq", value)
12
+ query.append(f"eq({field},{value})")
13
+ continue
14
+ op = tokens[-1]
15
+ if op not in constants.KEYWORDS:
16
+ # field__nested=value
17
+ field = ".".join(tokens)
18
+ value = rql_encode("eq", value)
19
+ query.append(f"eq({field},{value})")
20
+ continue
21
+ field = ".".join(tokens[:-1])
22
+ if op in constants.COMP or op in constants.SEARCH:
23
+ value = rql_encode(op, value)
24
+ query.append(f"{op}({field},{value})")
25
+ continue
26
+ if op in constants.LIST:
27
+ value = rql_encode(op, value)
28
+ query.append(f"{op}({field},({value}))")
29
+ continue
30
+
31
+ cmpop = "eq" if value is True else "ne"
32
+ expr = "null()" if op == constants.NULL else "empty()"
33
+ query.append(f"{cmpop}({field},{expr})")
34
+
35
+ return query
36
+
37
+
38
+ def rql_encode(op, value):
39
+ from datetime import date, datetime
40
+ from decimal import Decimal
41
+
42
+ if op not in constants.LIST:
43
+ if isinstance(value, str):
44
+ return value
45
+ if isinstance(value, bool):
46
+ return "true" if value else "false"
47
+ if isinstance(value, int | float | Decimal):
48
+ return str(value)
49
+ if isinstance(value, date | datetime):
50
+ return value.isoformat()
51
+ if op in constants.LIST and isinstance(value, list | tuple):
52
+ return ",".join(value)
53
+ raise TypeError(f"the `{op}` operator doesn't support the {type(value)} type.")
54
+
55
+
56
+ class RQLQuery:
57
+ """
58
+ Helper class to construct complex RQL queries.
59
+
60
+ Usage:
61
+
62
+ ```py3
63
+ rql = R(field='value', field2__in=('v1', 'v2'), field3__empty=True)
64
+ ```
65
+ !!! note
66
+ All the lookups expressed as keyword arguments are combined together with a logical `and`.
67
+
68
+
69
+ Using the ``n`` method:
70
+
71
+ ```py3
72
+ rql = (
73
+ R().n('field').eq('value')
74
+ & R().n('field2').anyof(('v1', 'v2'))
75
+ & R().n('field3').empty(True)
76
+ )
77
+ ```
78
+
79
+ The previous query can be expressed in a more concise form like:
80
+
81
+ ```py3
82
+ rql = R().field.eq('value') & R().field2.anyof(('v1', 'v2')) & r.field3.empty(True)
83
+ ```
84
+
85
+ ```py3
86
+ rql = R("field").eq("value")
87
+ ```
88
+
89
+ The R object support the bitwise operators `&`, `|` and `~`.
90
+
91
+ Nested fields can be expressed using dot notation:
92
+
93
+ ```py3
94
+ rql = R().n('nested.field').eq('value')
95
+ ```
96
+
97
+ or
98
+
99
+ ```py3
100
+ rql = R().nested.field.eq('value')
101
+ ```
102
+ """
103
+
104
+ AND = "and"
105
+ OR = "or"
106
+ EXPRESSION = "expr"
107
+
108
+ def __init__(
109
+ self,
110
+ _field=None,
111
+ *,
112
+ _op=EXPRESSION,
113
+ _children=None,
114
+ _negated=False,
115
+ _expr=None,
116
+ **kwargs,
117
+ ):
118
+ self.op = _op
119
+ self.children = _children or []
120
+ self.negated = _negated
121
+ self.expr = _expr
122
+ self._path = []
123
+ self._field = None
124
+ if _field:
125
+ self.n(_field)
126
+ if len(kwargs) == 1:
127
+ self.op = self.EXPRESSION
128
+ self.expr = parse_kwargs(kwargs)[0]
129
+ if len(kwargs) > 1:
130
+ self.op = self.AND
131
+ for token in parse_kwargs(kwargs):
132
+ self.children.append(RQLQuery(_expr=token))
133
+
134
+ def __len__(self):
135
+ if self.op == self.EXPRESSION:
136
+ if self.expr:
137
+ return 1
138
+ return 0
139
+ return len(self.children)
140
+
141
+ def __bool__(self):
142
+ return bool(self.children) or bool(self.expr)
143
+
144
+ def __eq__(self, other):
145
+ return (
146
+ self.op == other.op
147
+ and self.children == other.children
148
+ and self.negated == other.negated
149
+ and self.expr == other.expr
150
+ )
151
+
152
+ def __hash__(self):
153
+ return hash(
154
+ (
155
+ self.op,
156
+ self.expr,
157
+ self.negated,
158
+ *(hash(value) for value in self.children),
159
+ ),
160
+ )
161
+
162
+ def __repr__(self):
163
+ if self.op == self.EXPRESSION:
164
+ return f"<R({self.op}) {self.expr}>"
165
+ return f"<R({self.op})>"
166
+
167
+ def __and__(self, other):
168
+ return self._join(other, self.AND)
169
+
170
+ def __or__(self, other):
171
+ return self._join(other, self.OR)
172
+
173
+ def __invert__(self):
174
+ query = RQLQuery(_op=self.AND, _expr=self.expr, _negated=True)
175
+ query._append(self)
176
+ return query
177
+
178
+ def __getattr__(self, name):
179
+ return self.n(name)
180
+
181
+ def __str__(self):
182
+ return self._to_string(self)
183
+
184
+ def n(self, name):
185
+ """
186
+ Set the current field for this `R` object.
187
+
188
+ Args:
189
+ name (str): Name of the field.
190
+ """
191
+ if self._field:
192
+ raise AttributeError("Already evaluated")
193
+
194
+ self._path.extend(name.split("."))
195
+ return self
196
+
197
+ def ne(self, value):
198
+ """
199
+ Apply the `ne` operator to the field this `R` object refers to.
200
+
201
+ Args:
202
+ value (str): The value to which compare the field.
203
+ """
204
+ return self._bin("ne", value)
205
+
206
+ def eq(self, value):
207
+ """
208
+ Apply the `eq` operator to the field this `R` object refers to.
209
+
210
+ Args:
211
+ value (str): The value to which compare the field.
212
+ """
213
+ return self._bin("eq", value)
214
+
215
+ def lt(self, value):
216
+ """
217
+ Apply the `lt` operator to the field this `R` object refers to.
218
+
219
+ Args:
220
+ value (str): The value to which compare the field.
221
+ """
222
+ return self._bin("lt", value)
223
+
224
+ def le(self, value):
225
+ """
226
+ Apply the `le` operator to the field this `R` object refers to.
227
+
228
+ Args:
229
+ value (str): The value to which compare the field.
230
+ """
231
+ return self._bin("le", value)
232
+
233
+ def gt(self, value):
234
+ """
235
+ Apply the `gt` operator to the field this `R` object refers to.
236
+
237
+ Args:
238
+ value (str): The value to which compare the field.
239
+ """
240
+ return self._bin("gt", value)
241
+
242
+ def ge(self, value):
243
+ """
244
+ Apply the `ge` operator to the field this `R` object refers to.
245
+
246
+ Args:
247
+ value (str): The value to which compare the field.
248
+ """
249
+ return self._bin("ge", value)
250
+
251
+ def out(self, value: list[str]):
252
+ """
253
+ Apply the `out` operator to the field this `R` object refers to.
254
+
255
+ Args:
256
+ value (list[str]): The list of values to which compare the field.
257
+ """
258
+ return self._list("out", value)
259
+
260
+ def in_(self, value):
261
+ return self._list("in", value)
262
+
263
+ def oneof(self, value: list[str]):
264
+ """
265
+ Apply the `in` operator to the field this `R` object refers to.
266
+
267
+ Args:
268
+ value (list[str]): The list of values to which compare the field.
269
+ """
270
+ return self._list("in", value)
271
+
272
+ def null(self, value: list[str]):
273
+ """
274
+ Apply the `null` operator to the field this `R` object refers to.
275
+
276
+ Args:
277
+ value (list[str]): The value to which compare the field.
278
+ """
279
+ return self._bool("null", value)
280
+
281
+ def empty(self, value: bool = True):
282
+ """
283
+ Apply the `empty` operator to the field this `R` object refers to.
284
+
285
+ Usage: `R().field.empty()
286
+
287
+ For not empty: `R().field.empty(False)` or `R().field.not_empty()`
288
+ """
289
+ return self._bool("empty", value)
290
+
291
+ def not_empty(self):
292
+ """
293
+ Apply the `not_empty` operator to the field this `R` object refers to.
294
+ """
295
+ query = self._bool("empty", False)
296
+ return query
297
+
298
+ def like(self, value: list[str]):
299
+ """
300
+ Apply the `like` operator to the field this `R` object refers to.
301
+
302
+ Args:
303
+ value (list[str]): The value to which compare the field.
304
+ """
305
+ return self._bin("like", value)
306
+
307
+ def ilike(self, value: list[str]):
308
+ """
309
+ Apply the `ilike` operator to the field this `R` object refers to.
310
+
311
+ Args:
312
+ value (list[str]): The value to which compare the field.
313
+ """
314
+ return self._bin("ilike", value)
315
+
316
+ def _bin(self, op, value):
317
+ self._field = ".".join(self._path)
318
+ value = rql_encode(op, value)
319
+ self.expr = f"{op}({self._field},{value})"
320
+ return self
321
+
322
+ def _list(self, op, value):
323
+ self._field = ".".join(self._path)
324
+ value = rql_encode(op, value)
325
+ self.expr = f"{op}({self._field},({value}))"
326
+ return self
327
+
328
+ def _bool(self, expr, value):
329
+ self._field = ".".join(self._path)
330
+ if bool(value) is False:
331
+ self.expr = f"ne({self._field},{expr}())"
332
+ return self
333
+ self.expr = f"eq({self._field},{expr}())"
334
+ return self
335
+
336
+ def _to_string(self, query):
337
+ tokens = []
338
+ if query.expr:
339
+ if query.negated:
340
+ return f"not({query.expr})"
341
+ return query.expr
342
+ for c in query.children:
343
+ if c.expr:
344
+ if c.negated:
345
+ tokens.append(f"not({c.expr})")
346
+ else:
347
+ tokens.append(c.expr)
348
+ continue
349
+ tokens.append(self._to_string(c))
350
+
351
+ if not tokens:
352
+ return ""
353
+
354
+ if query.negated:
355
+ return f'not({query.op}({",".join(tokens)}))'
356
+ return f'{query.op}({",".join(tokens)})'
357
+
358
+ def _copy(self, other):
359
+ return RQLQuery(
360
+ _op=other.op,
361
+ _children=other.children[:],
362
+ _expr=other.expr,
363
+ )
364
+
365
+ def _join(self, other, op):
366
+ if self == other:
367
+ return self._copy(self)
368
+ if not other:
369
+ return self._copy(self)
370
+ if not self:
371
+ return self._copy(other)
372
+
373
+ query = RQLQuery(_op=op)
374
+ query._append(self)
375
+ query._append(other)
376
+ return query
377
+
378
+ def _append(self, other):
379
+ if other in self.children:
380
+ return other
381
+
382
+ if (
383
+ other.op == self.op or (len(other) == 1 and other.op != self.EXPRESSION)
384
+ ) and not other.negated:
385
+ self.children.extend(other.children)
386
+ return self
387
+
388
+ self.children.append(other)
389
+ return self
390
+
391
+
392
+ R = RQLQuery
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mpt-extension-sdk
3
- Version: 5.2.2
3
+ Version: 5.2.4
4
4
  Summary: Extensions SDK for SoftwareONE Marketplace Platform
5
5
  Author: SoftwareOne AG
6
6
  License: Apache-2.0 license
@@ -9,7 +9,6 @@ Requires-Python: <4,>=3.12
9
9
  Requires-Dist: azure-identity<2,>=1.21.0
10
10
  Requires-Dist: azure-keyvault-secrets<5,>=4.9.0
11
11
  Requires-Dist: azure-monitor-opentelemetry-exporter==1.0.0b25
12
- Requires-Dist: boto3==1.34.*
13
12
  Requires-Dist: click==8.1.*
14
13
  Requires-Dist: debugpy==1.8.*
15
14
  Requires-Dist: django-ninja==1.1.*
@@ -16,7 +16,7 @@ mpt_extension_sdk/key_vault/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
16
16
  mpt_extension_sdk/key_vault/base.py,sha256=RVG_Wiq-MrPyngJ4gfUd8oxoh1LUop1SvtCM2xdlx8M,3361
17
17
  mpt_extension_sdk/mpt_http/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  mpt_extension_sdk/mpt_http/base.py,sha256=3qgo9BW-uTRAbex26urMvLZU0fwnYnBprDRIJCHvTOk,1284
19
- mpt_extension_sdk/mpt_http/mpt.py,sha256=zIojPyOLBp1QJB8DXz2fx4P1c0yqfIuknyBOsKppcBg,12816
19
+ mpt_extension_sdk/mpt_http/mpt.py,sha256=NZABXnJ8EPq1uH72T3AQBsthUUvcJMKBtxbX-qLWqgY,12293
20
20
  mpt_extension_sdk/mpt_http/utils.py,sha256=3wJTT84CXYGjZw6FksNDX8tIHijkL3Wcmld9r6Iz0xc,95
21
21
  mpt_extension_sdk/mpt_http/wrap_http_error.py,sha256=j8K6Ddx7NiM-FPRMQi25vuULAW8LXxzZ4EwuIJufxis,1801
22
22
  mpt_extension_sdk/runtime/__init__.py,sha256=PQSAz9qvXHbxrn4KvuXSHB8y-A4Jpgbm6ZV-wPiNPyw,194
@@ -33,17 +33,20 @@ mpt_extension_sdk/runtime/djapp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
33
33
  mpt_extension_sdk/runtime/djapp/apps.py,sha256=YA1G5HaRqFBS-0DfYQuFpMgzUCYpu5T8x5LEC6MwI_M,1398
34
34
  mpt_extension_sdk/runtime/djapp/middleware.py,sha256=oAA5khXW6xeUjnOV63pNCF4D7QFVD6PayIa_489KRmg,555
35
35
  mpt_extension_sdk/runtime/djapp/conf/__init__.py,sha256=_sHo76rGeXSTH8bW3pacyGFfNYSln8oLRwOSstYOmco,350
36
- mpt_extension_sdk/runtime/djapp/conf/default.py,sha256=Io-dz0ylmVY_3tpZm0_K5JcxZXHlgeW1RFwAXMchCro,6167
37
- mpt_extension_sdk/runtime/djapp/conf/urls.py,sha256=x-LDNfqckwvnEqHVFk8DttDZpYWjoF_JbJgu_itJSZE,310
36
+ mpt_extension_sdk/runtime/djapp/conf/default.py,sha256=9eAB_hRnkok2I7E1NjYHs3x8ifrVc4_ihosm37Qq7Zo,6405
37
+ mpt_extension_sdk/runtime/djapp/conf/urls.py,sha256=g-h1vzwDgCGLliSE2BDjb1eRJevZxZ7ehJrqSis12So,309
38
38
  mpt_extension_sdk/runtime/djapp/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  mpt_extension_sdk/runtime/djapp/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
40
  mpt_extension_sdk/runtime/djapp/management/commands/consume_events.py,sha256=BVb4sgKI2Ep759bDcOH5Qm1xJEewc5-bNt_snspV2ck,1229
41
41
  mpt_extension_sdk/runtime/events/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
42
  mpt_extension_sdk/runtime/events/dispatcher.py,sha256=ZMswk50vGGfUgKeQ2Cc3k9wtrm63z0OH7EtlKCkWQYM,3008
43
- mpt_extension_sdk/runtime/events/producers.py,sha256=dv-PWN9hKOBxT6nyLWezjZxUq6NpPz8Jq-cOiVEcDUY,3604
43
+ mpt_extension_sdk/runtime/events/producers.py,sha256=amTUJxTYkePNMQEZ6yP9iCN_0Wk2dpGNl32kBwJS5qE,3654
44
44
  mpt_extension_sdk/runtime/events/utils.py,sha256=bxFo-iQUqEJDqcIotC88Ty3Xt0K2FyYjA9UMWFEyMKI,2663
45
- mpt_extension_sdk-5.2.2.dist-info/METADATA,sha256=BKkSIxFuVCmJaaHIZtwjJbpxajx8RmjlFV4PjIK2BHw,1386
46
- mpt_extension_sdk-5.2.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
47
- mpt_extension_sdk-5.2.2.dist-info/entry_points.txt,sha256=N8T9gBssEOm_UeBf9ABbGqtlnethrumfMoL4hNYWVFA,146
48
- mpt_extension_sdk-5.2.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
49
- mpt_extension_sdk-5.2.2.dist-info/RECORD,,
45
+ mpt_extension_sdk/swo_rql/__init__.py,sha256=QrvRDYhpK-Pd3OF-U2aMeazuKm_kbvXwLRIjd9Mm6ok,104
46
+ mpt_extension_sdk/swo_rql/constants.py,sha256=39BZ78OzdU_dIQtoy-Z_5utXqEXRweIFvM9Zfxg9j5M,171
47
+ mpt_extension_sdk/swo_rql/query_builder.py,sha256=XAoMYV1jaAouYjpqrh8nMaDNzD0as-BhMx8rsvdeZ0k,10500
48
+ mpt_extension_sdk-5.2.4.dist-info/METADATA,sha256=CY_PBVb6d2yRBIrZjGMQU5xHtTDn0QQG-gIBlJithxk,1357
49
+ mpt_extension_sdk-5.2.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
50
+ mpt_extension_sdk-5.2.4.dist-info/entry_points.txt,sha256=MwL1GQnaWIXHSSxWx1gR7Q-NdFsh_451NgIO2l_ymZ4,146
51
+ mpt_extension_sdk-5.2.4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
52
+ mpt_extension_sdk-5.2.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  [console_scripts]
2
- swoext = mpt_extension_sdk.runtime.swoext:main
2
+ swosdk = mpt_extension_sdk.runtime.swoext:main
3
3
 
4
4
  [swo.mpt.sdk]
5
5
  app_config = mpt_extension_sdk.runtime.djapp.apps:ExtensionConfig