dub 0.33.0__py3-none-any.whl → 0.34.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.
- dub/_version.py +3 -3
- dub/analytics.py +2 -0
- dub/basesdk.py +6 -0
- dub/bounties.py +841 -0
- dub/commissions.py +4 -0
- dub/customers.py +8 -0
- dub/domains.py +12 -0
- dub/embed_tokens.py +2 -0
- dub/events.py +2 -0
- dub/folders.py +8 -0
- dub/links.py +20 -0
- dub/models/components/__init__.py +55 -149
- dub/models/components/commissioncreatedevent.py +29 -1
- dub/models/components/leadcreatedevent.py +8 -8
- dub/models/components/linkclickedevent.py +12 -12
- dub/models/components/linkerrorschema.py +12 -12
- dub/models/components/linkschema.py +3 -3
- dub/models/components/linktagschema.py +3 -3
- dub/models/components/linktagschemaoutput.py +38 -0
- dub/models/components/linkwebhookevent.py +8 -10
- dub/models/components/partnerenrolledevent.py +4 -4
- dub/models/components/salecreatedevent.py +8 -8
- dub/models/operations/__init__.py +223 -22
- dub/models/operations/approvebountysubmission.py +185 -0
- dub/models/operations/createpartner.py +4 -55
- dub/models/operations/createpartnerlink.py +0 -51
- dub/models/operations/createreferralsembedtoken.py +0 -51
- dub/models/operations/getcustomers.py +18 -0
- dub/models/operations/getlinkinfo.py +0 -2
- dub/models/operations/getlinks.py +2 -2
- dub/models/operations/getlinkscount.py +2 -2
- dub/models/operations/getqrcode.py +1 -1
- dub/models/operations/listbountysubmissions.py +212 -0
- dub/models/operations/listdomains.py +1 -1
- dub/models/operations/listevents.py +2016 -21
- dub/models/operations/listpartners.py +4 -4
- dub/models/operations/rejectbountysubmission.py +174 -0
- dub/models/operations/retrieveanalytics.py +16 -5
- dub/models/operations/retrievelinks.py +2 -2
- dub/models/operations/tracklead.py +4 -4
- dub/models/operations/updatecustomer.py +23 -11
- dub/models/operations/updatelink.py +0 -2
- dub/models/operations/updateworkspace.py +3 -3
- dub/models/operations/upsertpartnerlink.py +7 -65
- dub/partners.py +22 -4
- dub/qr_codes.py +2 -0
- dub/sdk.py +3 -0
- dub/tags.py +24 -12
- dub/track.py +4 -0
- dub/types/basemodel.py +41 -3
- dub/utils/__init__.py +0 -3
- dub/utils/enums.py +60 -0
- dub/utils/forms.py +21 -10
- dub/utils/queryparams.py +14 -2
- dub/utils/requestbodies.py +3 -3
- dub/utils/serializers.py +0 -20
- dub/workspaces.py +4 -0
- {dub-0.33.0.dist-info → dub-0.34.1.dist-info}/METADATA +20 -14
- {dub-0.33.0.dist-info → dub-0.34.1.dist-info}/RECORD +61 -60
- dub/models/components/clickevent.py +0 -557
- dub/models/components/continentcode.py +0 -16
- dub/models/components/leadevent.py +0 -681
- dub/models/components/saleevent.py +0 -780
- {dub-0.33.0.dist-info → dub-0.34.1.dist-info}/WHEEL +0 -0
- {dub-0.33.0.dist-info → dub-0.34.1.dist-info}/licenses/LICENSE +0 -0
dub/partners.py
CHANGED
|
@@ -70,6 +70,7 @@ class Partners(BaseSDK):
|
|
|
70
70
|
"json",
|
|
71
71
|
Optional[operations.CreatePartnerRequestBody],
|
|
72
72
|
),
|
|
73
|
+
allow_empty_value=None,
|
|
73
74
|
timeout_ms=timeout_ms,
|
|
74
75
|
)
|
|
75
76
|
|
|
@@ -213,6 +214,7 @@ class Partners(BaseSDK):
|
|
|
213
214
|
"json",
|
|
214
215
|
Optional[operations.CreatePartnerRequestBody],
|
|
215
216
|
),
|
|
217
|
+
allow_empty_value=None,
|
|
216
218
|
timeout_ms=timeout_ms,
|
|
217
219
|
)
|
|
218
220
|
|
|
@@ -344,6 +346,7 @@ class Partners(BaseSDK):
|
|
|
344
346
|
accept_header_value="application/json",
|
|
345
347
|
http_headers=http_headers,
|
|
346
348
|
security=self.sdk_configuration.security,
|
|
349
|
+
allow_empty_value=None,
|
|
347
350
|
timeout_ms=timeout_ms,
|
|
348
351
|
)
|
|
349
352
|
|
|
@@ -475,6 +478,7 @@ class Partners(BaseSDK):
|
|
|
475
478
|
accept_header_value="application/json",
|
|
476
479
|
http_headers=http_headers,
|
|
477
480
|
security=self.sdk_configuration.security,
|
|
481
|
+
allow_empty_value=None,
|
|
478
482
|
timeout_ms=timeout_ms,
|
|
479
483
|
)
|
|
480
484
|
|
|
@@ -618,6 +622,7 @@ class Partners(BaseSDK):
|
|
|
618
622
|
"json",
|
|
619
623
|
Optional[operations.CreatePartnerLinkRequestBody],
|
|
620
624
|
),
|
|
625
|
+
allow_empty_value=None,
|
|
621
626
|
timeout_ms=timeout_ms,
|
|
622
627
|
)
|
|
623
628
|
|
|
@@ -759,6 +764,7 @@ class Partners(BaseSDK):
|
|
|
759
764
|
"json",
|
|
760
765
|
Optional[operations.CreatePartnerLinkRequestBody],
|
|
761
766
|
),
|
|
767
|
+
allow_empty_value=None,
|
|
762
768
|
timeout_ms=timeout_ms,
|
|
763
769
|
)
|
|
764
770
|
|
|
@@ -850,7 +856,7 @@ class Partners(BaseSDK):
|
|
|
850
856
|
server_url: Optional[str] = None,
|
|
851
857
|
timeout_ms: Optional[int] = None,
|
|
852
858
|
http_headers: Optional[Mapping[str, str]] = None,
|
|
853
|
-
) -> List[operations.
|
|
859
|
+
) -> List[operations.RetrieveLinksResponseBody]:
|
|
854
860
|
r"""Retrieve a partner's links.
|
|
855
861
|
|
|
856
862
|
Retrieve a partner's links by their partner ID or tenant ID.
|
|
@@ -888,6 +894,7 @@ class Partners(BaseSDK):
|
|
|
888
894
|
accept_header_value="application/json",
|
|
889
895
|
http_headers=http_headers,
|
|
890
896
|
security=self.sdk_configuration.security,
|
|
897
|
+
allow_empty_value=None,
|
|
891
898
|
timeout_ms=timeout_ms,
|
|
892
899
|
)
|
|
893
900
|
|
|
@@ -926,7 +933,9 @@ class Partners(BaseSDK):
|
|
|
926
933
|
|
|
927
934
|
response_data: Any = None
|
|
928
935
|
if utils.match_response(http_res, "200", "application/json"):
|
|
929
|
-
return unmarshal_json_response(
|
|
936
|
+
return unmarshal_json_response(
|
|
937
|
+
List[operations.RetrieveLinksResponseBody], http_res
|
|
938
|
+
)
|
|
930
939
|
if utils.match_response(http_res, "400", "application/json"):
|
|
931
940
|
response_data = unmarshal_json_response(errors.BadRequestData, http_res)
|
|
932
941
|
raise errors.BadRequest(response_data, http_res)
|
|
@@ -979,7 +988,7 @@ class Partners(BaseSDK):
|
|
|
979
988
|
server_url: Optional[str] = None,
|
|
980
989
|
timeout_ms: Optional[int] = None,
|
|
981
990
|
http_headers: Optional[Mapping[str, str]] = None,
|
|
982
|
-
) -> List[operations.
|
|
991
|
+
) -> List[operations.RetrieveLinksResponseBody]:
|
|
983
992
|
r"""Retrieve a partner's links.
|
|
984
993
|
|
|
985
994
|
Retrieve a partner's links by their partner ID or tenant ID.
|
|
@@ -1017,6 +1026,7 @@ class Partners(BaseSDK):
|
|
|
1017
1026
|
accept_header_value="application/json",
|
|
1018
1027
|
http_headers=http_headers,
|
|
1019
1028
|
security=self.sdk_configuration.security,
|
|
1029
|
+
allow_empty_value=None,
|
|
1020
1030
|
timeout_ms=timeout_ms,
|
|
1021
1031
|
)
|
|
1022
1032
|
|
|
@@ -1055,7 +1065,9 @@ class Partners(BaseSDK):
|
|
|
1055
1065
|
|
|
1056
1066
|
response_data: Any = None
|
|
1057
1067
|
if utils.match_response(http_res, "200", "application/json"):
|
|
1058
|
-
return unmarshal_json_response(
|
|
1068
|
+
return unmarshal_json_response(
|
|
1069
|
+
List[operations.RetrieveLinksResponseBody], http_res
|
|
1070
|
+
)
|
|
1059
1071
|
if utils.match_response(http_res, "400", "application/json"):
|
|
1060
1072
|
response_data = unmarshal_json_response(errors.BadRequestData, http_res)
|
|
1061
1073
|
raise errors.BadRequest(response_data, http_res)
|
|
@@ -1158,6 +1170,7 @@ class Partners(BaseSDK):
|
|
|
1158
1170
|
"json",
|
|
1159
1171
|
Optional[operations.UpsertPartnerLinkRequestBody],
|
|
1160
1172
|
),
|
|
1173
|
+
allow_empty_value=None,
|
|
1161
1174
|
timeout_ms=timeout_ms,
|
|
1162
1175
|
)
|
|
1163
1176
|
|
|
@@ -1299,6 +1312,7 @@ class Partners(BaseSDK):
|
|
|
1299
1312
|
"json",
|
|
1300
1313
|
Optional[operations.UpsertPartnerLinkRequestBody],
|
|
1301
1314
|
),
|
|
1315
|
+
allow_empty_value=None,
|
|
1302
1316
|
timeout_ms=timeout_ms,
|
|
1303
1317
|
)
|
|
1304
1318
|
|
|
@@ -1431,6 +1445,7 @@ class Partners(BaseSDK):
|
|
|
1431
1445
|
accept_header_value="application/json",
|
|
1432
1446
|
http_headers=http_headers,
|
|
1433
1447
|
security=self.sdk_configuration.security,
|
|
1448
|
+
allow_empty_value=None,
|
|
1434
1449
|
timeout_ms=timeout_ms,
|
|
1435
1450
|
)
|
|
1436
1451
|
|
|
@@ -1565,6 +1580,7 @@ class Partners(BaseSDK):
|
|
|
1565
1580
|
accept_header_value="application/json",
|
|
1566
1581
|
http_headers=http_headers,
|
|
1567
1582
|
security=self.sdk_configuration.security,
|
|
1583
|
+
allow_empty_value=None,
|
|
1568
1584
|
timeout_ms=timeout_ms,
|
|
1569
1585
|
)
|
|
1570
1586
|
|
|
@@ -1704,6 +1720,7 @@ class Partners(BaseSDK):
|
|
|
1704
1720
|
get_serialized_body=lambda: utils.serialize_request_body(
|
|
1705
1721
|
request, False, True, "json", Optional[operations.BanPartnerRequestBody]
|
|
1706
1722
|
),
|
|
1723
|
+
allow_empty_value=None,
|
|
1707
1724
|
timeout_ms=timeout_ms,
|
|
1708
1725
|
)
|
|
1709
1726
|
|
|
@@ -1841,6 +1858,7 @@ class Partners(BaseSDK):
|
|
|
1841
1858
|
get_serialized_body=lambda: utils.serialize_request_body(
|
|
1842
1859
|
request, False, True, "json", Optional[operations.BanPartnerRequestBody]
|
|
1843
1860
|
),
|
|
1861
|
+
allow_empty_value=None,
|
|
1844
1862
|
timeout_ms=timeout_ms,
|
|
1845
1863
|
)
|
|
1846
1864
|
|
dub/qr_codes.py
CHANGED
|
@@ -58,6 +58,7 @@ class QRCodes(BaseSDK):
|
|
|
58
58
|
accept_header_value="image/png",
|
|
59
59
|
http_headers=http_headers,
|
|
60
60
|
security=self.sdk_configuration.security,
|
|
61
|
+
allow_empty_value=None,
|
|
61
62
|
timeout_ms=timeout_ms,
|
|
62
63
|
)
|
|
63
64
|
|
|
@@ -187,6 +188,7 @@ class QRCodes(BaseSDK):
|
|
|
187
188
|
accept_header_value="image/png",
|
|
188
189
|
http_headers=http_headers,
|
|
189
190
|
security=self.sdk_configuration.security,
|
|
191
|
+
allow_empty_value=None,
|
|
190
192
|
timeout_ms=timeout_ms,
|
|
191
193
|
)
|
|
192
194
|
|
dub/sdk.py
CHANGED
|
@@ -17,6 +17,7 @@ import weakref
|
|
|
17
17
|
|
|
18
18
|
if TYPE_CHECKING:
|
|
19
19
|
from dub.analytics import Analytics
|
|
20
|
+
from dub.bounties import Bounties
|
|
20
21
|
from dub.commissions import Commissions
|
|
21
22
|
from dub.customers import Customers
|
|
22
23
|
from dub.domains import Domains
|
|
@@ -47,6 +48,7 @@ class Dub(BaseSDK):
|
|
|
47
48
|
workspaces: "Workspaces"
|
|
48
49
|
embed_tokens: "EmbedTokens"
|
|
49
50
|
qr_codes: "QRCodes"
|
|
51
|
+
bounties: "Bounties"
|
|
50
52
|
_sub_sdk_map = {
|
|
51
53
|
"links": ("dub.links", "Links"),
|
|
52
54
|
"analytics": ("dub.analytics", "Analytics"),
|
|
@@ -61,6 +63,7 @@ class Dub(BaseSDK):
|
|
|
61
63
|
"workspaces": ("dub.workspaces", "Workspaces"),
|
|
62
64
|
"embed_tokens": ("dub.embed_tokens", "EmbedTokens"),
|
|
63
65
|
"qr_codes": ("dub.qr_codes", "QRCodes"),
|
|
66
|
+
"bounties": ("dub.bounties", "Bounties"),
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
def __init__(
|
dub/tags.py
CHANGED
|
@@ -23,7 +23,7 @@ class Tags(BaseSDK):
|
|
|
23
23
|
server_url: Optional[str] = None,
|
|
24
24
|
timeout_ms: Optional[int] = None,
|
|
25
25
|
http_headers: Optional[Mapping[str, str]] = None,
|
|
26
|
-
) -> components.
|
|
26
|
+
) -> components.LinkTagSchemaOutput:
|
|
27
27
|
r"""Create a tag
|
|
28
28
|
|
|
29
29
|
Create a tag for the authenticated workspace.
|
|
@@ -66,6 +66,7 @@ class Tags(BaseSDK):
|
|
|
66
66
|
get_serialized_body=lambda: utils.serialize_request_body(
|
|
67
67
|
request, False, True, "json", Optional[operations.CreateTagRequestBody]
|
|
68
68
|
),
|
|
69
|
+
allow_empty_value=None,
|
|
69
70
|
timeout_ms=timeout_ms,
|
|
70
71
|
)
|
|
71
72
|
|
|
@@ -104,7 +105,7 @@ class Tags(BaseSDK):
|
|
|
104
105
|
|
|
105
106
|
response_data: Any = None
|
|
106
107
|
if utils.match_response(http_res, "201", "application/json"):
|
|
107
|
-
return unmarshal_json_response(components.
|
|
108
|
+
return unmarshal_json_response(components.LinkTagSchemaOutput, http_res)
|
|
108
109
|
if utils.match_response(http_res, "400", "application/json"):
|
|
109
110
|
response_data = unmarshal_json_response(errors.BadRequestData, http_res)
|
|
110
111
|
raise errors.BadRequest(response_data, http_res)
|
|
@@ -160,7 +161,7 @@ class Tags(BaseSDK):
|
|
|
160
161
|
server_url: Optional[str] = None,
|
|
161
162
|
timeout_ms: Optional[int] = None,
|
|
162
163
|
http_headers: Optional[Mapping[str, str]] = None,
|
|
163
|
-
) -> components.
|
|
164
|
+
) -> components.LinkTagSchemaOutput:
|
|
164
165
|
r"""Create a tag
|
|
165
166
|
|
|
166
167
|
Create a tag for the authenticated workspace.
|
|
@@ -203,6 +204,7 @@ class Tags(BaseSDK):
|
|
|
203
204
|
get_serialized_body=lambda: utils.serialize_request_body(
|
|
204
205
|
request, False, True, "json", Optional[operations.CreateTagRequestBody]
|
|
205
206
|
),
|
|
207
|
+
allow_empty_value=None,
|
|
206
208
|
timeout_ms=timeout_ms,
|
|
207
209
|
)
|
|
208
210
|
|
|
@@ -241,7 +243,7 @@ class Tags(BaseSDK):
|
|
|
241
243
|
|
|
242
244
|
response_data: Any = None
|
|
243
245
|
if utils.match_response(http_res, "201", "application/json"):
|
|
244
|
-
return unmarshal_json_response(components.
|
|
246
|
+
return unmarshal_json_response(components.LinkTagSchemaOutput, http_res)
|
|
245
247
|
if utils.match_response(http_res, "400", "application/json"):
|
|
246
248
|
response_data = unmarshal_json_response(errors.BadRequestData, http_res)
|
|
247
249
|
raise errors.BadRequest(response_data, http_res)
|
|
@@ -292,7 +294,7 @@ class Tags(BaseSDK):
|
|
|
292
294
|
server_url: Optional[str] = None,
|
|
293
295
|
timeout_ms: Optional[int] = None,
|
|
294
296
|
http_headers: Optional[Mapping[str, str]] = None,
|
|
295
|
-
) -> List[components.
|
|
297
|
+
) -> List[components.LinkTagSchemaOutput]:
|
|
296
298
|
r"""Retrieve a list of tags
|
|
297
299
|
|
|
298
300
|
Retrieve a list of tags for the authenticated workspace.
|
|
@@ -330,6 +332,7 @@ class Tags(BaseSDK):
|
|
|
330
332
|
accept_header_value="application/json",
|
|
331
333
|
http_headers=http_headers,
|
|
332
334
|
security=self.sdk_configuration.security,
|
|
335
|
+
allow_empty_value=None,
|
|
333
336
|
timeout_ms=timeout_ms,
|
|
334
337
|
)
|
|
335
338
|
|
|
@@ -368,7 +371,9 @@ class Tags(BaseSDK):
|
|
|
368
371
|
|
|
369
372
|
response_data: Any = None
|
|
370
373
|
if utils.match_response(http_res, "200", "application/json"):
|
|
371
|
-
return unmarshal_json_response(
|
|
374
|
+
return unmarshal_json_response(
|
|
375
|
+
List[components.LinkTagSchemaOutput], http_res
|
|
376
|
+
)
|
|
372
377
|
if utils.match_response(http_res, "400", "application/json"):
|
|
373
378
|
response_data = unmarshal_json_response(errors.BadRequestData, http_res)
|
|
374
379
|
raise errors.BadRequest(response_data, http_res)
|
|
@@ -419,7 +424,7 @@ class Tags(BaseSDK):
|
|
|
419
424
|
server_url: Optional[str] = None,
|
|
420
425
|
timeout_ms: Optional[int] = None,
|
|
421
426
|
http_headers: Optional[Mapping[str, str]] = None,
|
|
422
|
-
) -> List[components.
|
|
427
|
+
) -> List[components.LinkTagSchemaOutput]:
|
|
423
428
|
r"""Retrieve a list of tags
|
|
424
429
|
|
|
425
430
|
Retrieve a list of tags for the authenticated workspace.
|
|
@@ -457,6 +462,7 @@ class Tags(BaseSDK):
|
|
|
457
462
|
accept_header_value="application/json",
|
|
458
463
|
http_headers=http_headers,
|
|
459
464
|
security=self.sdk_configuration.security,
|
|
465
|
+
allow_empty_value=None,
|
|
460
466
|
timeout_ms=timeout_ms,
|
|
461
467
|
)
|
|
462
468
|
|
|
@@ -495,7 +501,9 @@ class Tags(BaseSDK):
|
|
|
495
501
|
|
|
496
502
|
response_data: Any = None
|
|
497
503
|
if utils.match_response(http_res, "200", "application/json"):
|
|
498
|
-
return unmarshal_json_response(
|
|
504
|
+
return unmarshal_json_response(
|
|
505
|
+
List[components.LinkTagSchemaOutput], http_res
|
|
506
|
+
)
|
|
499
507
|
if utils.match_response(http_res, "400", "application/json"):
|
|
500
508
|
response_data = unmarshal_json_response(errors.BadRequestData, http_res)
|
|
501
509
|
raise errors.BadRequest(response_data, http_res)
|
|
@@ -552,7 +560,7 @@ class Tags(BaseSDK):
|
|
|
552
560
|
server_url: Optional[str] = None,
|
|
553
561
|
timeout_ms: Optional[int] = None,
|
|
554
562
|
http_headers: Optional[Mapping[str, str]] = None,
|
|
555
|
-
) -> components.
|
|
563
|
+
) -> components.LinkTagSchemaOutput:
|
|
556
564
|
r"""Update a tag
|
|
557
565
|
|
|
558
566
|
Update a tag in the workspace.
|
|
@@ -601,6 +609,7 @@ class Tags(BaseSDK):
|
|
|
601
609
|
"json",
|
|
602
610
|
Optional[operations.UpdateTagRequestBody],
|
|
603
611
|
),
|
|
612
|
+
allow_empty_value=None,
|
|
604
613
|
timeout_ms=timeout_ms,
|
|
605
614
|
)
|
|
606
615
|
|
|
@@ -639,7 +648,7 @@ class Tags(BaseSDK):
|
|
|
639
648
|
|
|
640
649
|
response_data: Any = None
|
|
641
650
|
if utils.match_response(http_res, "200", "application/json"):
|
|
642
|
-
return unmarshal_json_response(components.
|
|
651
|
+
return unmarshal_json_response(components.LinkTagSchemaOutput, http_res)
|
|
643
652
|
if utils.match_response(http_res, "400", "application/json"):
|
|
644
653
|
response_data = unmarshal_json_response(errors.BadRequestData, http_res)
|
|
645
654
|
raise errors.BadRequest(response_data, http_res)
|
|
@@ -696,7 +705,7 @@ class Tags(BaseSDK):
|
|
|
696
705
|
server_url: Optional[str] = None,
|
|
697
706
|
timeout_ms: Optional[int] = None,
|
|
698
707
|
http_headers: Optional[Mapping[str, str]] = None,
|
|
699
|
-
) -> components.
|
|
708
|
+
) -> components.LinkTagSchemaOutput:
|
|
700
709
|
r"""Update a tag
|
|
701
710
|
|
|
702
711
|
Update a tag in the workspace.
|
|
@@ -745,6 +754,7 @@ class Tags(BaseSDK):
|
|
|
745
754
|
"json",
|
|
746
755
|
Optional[operations.UpdateTagRequestBody],
|
|
747
756
|
),
|
|
757
|
+
allow_empty_value=None,
|
|
748
758
|
timeout_ms=timeout_ms,
|
|
749
759
|
)
|
|
750
760
|
|
|
@@ -783,7 +793,7 @@ class Tags(BaseSDK):
|
|
|
783
793
|
|
|
784
794
|
response_data: Any = None
|
|
785
795
|
if utils.match_response(http_res, "200", "application/json"):
|
|
786
|
-
return unmarshal_json_response(components.
|
|
796
|
+
return unmarshal_json_response(components.LinkTagSchemaOutput, http_res)
|
|
787
797
|
if utils.match_response(http_res, "400", "application/json"):
|
|
788
798
|
response_data = unmarshal_json_response(errors.BadRequestData, http_res)
|
|
789
799
|
raise errors.BadRequest(response_data, http_res)
|
|
@@ -872,6 +882,7 @@ class Tags(BaseSDK):
|
|
|
872
882
|
accept_header_value="application/json",
|
|
873
883
|
http_headers=http_headers,
|
|
874
884
|
security=self.sdk_configuration.security,
|
|
885
|
+
allow_empty_value=None,
|
|
875
886
|
timeout_ms=timeout_ms,
|
|
876
887
|
)
|
|
877
888
|
|
|
@@ -999,6 +1010,7 @@ class Tags(BaseSDK):
|
|
|
999
1010
|
accept_header_value="application/json",
|
|
1000
1011
|
http_headers=http_headers,
|
|
1001
1012
|
security=self.sdk_configuration.security,
|
|
1013
|
+
allow_empty_value=None,
|
|
1002
1014
|
timeout_ms=timeout_ms,
|
|
1003
1015
|
)
|
|
1004
1016
|
|
dub/track.py
CHANGED
|
@@ -66,6 +66,7 @@ class Track(BaseSDK):
|
|
|
66
66
|
get_serialized_body=lambda: utils.serialize_request_body(
|
|
67
67
|
request, False, True, "json", Optional[operations.TrackLeadRequestBody]
|
|
68
68
|
),
|
|
69
|
+
allow_empty_value=None,
|
|
69
70
|
timeout_ms=timeout_ms,
|
|
70
71
|
)
|
|
71
72
|
|
|
@@ -203,6 +204,7 @@ class Track(BaseSDK):
|
|
|
203
204
|
get_serialized_body=lambda: utils.serialize_request_body(
|
|
204
205
|
request, False, True, "json", Optional[operations.TrackLeadRequestBody]
|
|
205
206
|
),
|
|
207
|
+
allow_empty_value=None,
|
|
206
208
|
timeout_ms=timeout_ms,
|
|
207
209
|
)
|
|
208
210
|
|
|
@@ -340,6 +342,7 @@ class Track(BaseSDK):
|
|
|
340
342
|
get_serialized_body=lambda: utils.serialize_request_body(
|
|
341
343
|
request, False, True, "json", Optional[operations.TrackSaleRequestBody]
|
|
342
344
|
),
|
|
345
|
+
allow_empty_value=None,
|
|
343
346
|
timeout_ms=timeout_ms,
|
|
344
347
|
)
|
|
345
348
|
|
|
@@ -477,6 +480,7 @@ class Track(BaseSDK):
|
|
|
477
480
|
get_serialized_body=lambda: utils.serialize_request_body(
|
|
478
481
|
request, False, True, "json", Optional[operations.TrackSaleRequestBody]
|
|
479
482
|
),
|
|
483
|
+
allow_empty_value=None,
|
|
480
484
|
timeout_ms=timeout_ms,
|
|
481
485
|
)
|
|
482
486
|
|
dub/types/basemodel.py
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from pydantic import ConfigDict, model_serializer
|
|
4
4
|
from pydantic import BaseModel as PydanticBaseModel
|
|
5
|
-
from
|
|
5
|
+
from pydantic_core import core_schema
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Literal, Optional, TypeVar, Union
|
|
6
7
|
from typing_extensions import TypeAliasType, TypeAlias
|
|
7
8
|
|
|
8
9
|
|
|
@@ -35,5 +36,42 @@ else:
|
|
|
35
36
|
"OptionalNullable", Union[Optional[Nullable[T]], Unset], type_params=(T,)
|
|
36
37
|
)
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
UnrecognizedStr:
|
|
39
|
+
|
|
40
|
+
class UnrecognizedStr(str):
|
|
41
|
+
@classmethod
|
|
42
|
+
def __get_pydantic_core_schema__(cls, _source_type: Any, _handler: Any) -> core_schema.CoreSchema:
|
|
43
|
+
# Make UnrecognizedStr only work in lax mode, not strict mode
|
|
44
|
+
# This makes it a "fallback" option when more specific types (like Literals) don't match
|
|
45
|
+
def validate_lax(v: Any) -> 'UnrecognizedStr':
|
|
46
|
+
if isinstance(v, cls):
|
|
47
|
+
return v
|
|
48
|
+
return cls(str(v))
|
|
49
|
+
|
|
50
|
+
# Use lax_or_strict_schema where strict always fails
|
|
51
|
+
# This forces Pydantic to prefer other union members in strict mode
|
|
52
|
+
# and only fall back to UnrecognizedStr in lax mode
|
|
53
|
+
return core_schema.lax_or_strict_schema(
|
|
54
|
+
lax_schema=core_schema.chain_schema([
|
|
55
|
+
core_schema.str_schema(),
|
|
56
|
+
core_schema.no_info_plain_validator_function(validate_lax)
|
|
57
|
+
]),
|
|
58
|
+
strict_schema=core_schema.none_schema(), # Always fails in strict mode
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class UnrecognizedInt(int):
|
|
63
|
+
@classmethod
|
|
64
|
+
def __get_pydantic_core_schema__(cls, _source_type: Any, _handler: Any) -> core_schema.CoreSchema:
|
|
65
|
+
# Make UnrecognizedInt only work in lax mode, not strict mode
|
|
66
|
+
# This makes it a "fallback" option when more specific types (like Literals) don't match
|
|
67
|
+
def validate_lax(v: Any) -> 'UnrecognizedInt':
|
|
68
|
+
if isinstance(v, cls):
|
|
69
|
+
return v
|
|
70
|
+
return cls(int(v))
|
|
71
|
+
return core_schema.lax_or_strict_schema(
|
|
72
|
+
lax_schema=core_schema.chain_schema([
|
|
73
|
+
core_schema.int_schema(),
|
|
74
|
+
core_schema.no_info_plain_validator_function(validate_lax)
|
|
75
|
+
]),
|
|
76
|
+
strict_schema=core_schema.none_schema(), # Always fails in strict mode
|
|
77
|
+
)
|
dub/utils/__init__.py
CHANGED
|
@@ -41,7 +41,6 @@ if TYPE_CHECKING:
|
|
|
41
41
|
validate_decimal,
|
|
42
42
|
validate_float,
|
|
43
43
|
validate_int,
|
|
44
|
-
validate_open_enum,
|
|
45
44
|
)
|
|
46
45
|
from .url import generate_url, template_url, remove_suffix
|
|
47
46
|
from .values import (
|
|
@@ -102,7 +101,6 @@ __all__ = [
|
|
|
102
101
|
"validate_const",
|
|
103
102
|
"validate_float",
|
|
104
103
|
"validate_int",
|
|
105
|
-
"validate_open_enum",
|
|
106
104
|
"cast_partial",
|
|
107
105
|
]
|
|
108
106
|
|
|
@@ -155,7 +153,6 @@ _dynamic_imports: dict[str, str] = {
|
|
|
155
153
|
"validate_const": ".serializers",
|
|
156
154
|
"validate_float": ".serializers",
|
|
157
155
|
"validate_int": ".serializers",
|
|
158
|
-
"validate_open_enum": ".serializers",
|
|
159
156
|
"cast_partial": ".values",
|
|
160
157
|
}
|
|
161
158
|
|
dub/utils/enums.py
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import enum
|
|
4
4
|
import sys
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from pydantic_core import core_schema
|
|
8
|
+
|
|
5
9
|
|
|
6
10
|
class OpenEnumMeta(enum.EnumMeta):
|
|
7
11
|
# The __call__ method `boundary` kwarg was added in 3.11 and must be present
|
|
@@ -72,3 +76,59 @@ class OpenEnumMeta(enum.EnumMeta):
|
|
|
72
76
|
)
|
|
73
77
|
except ValueError:
|
|
74
78
|
return value
|
|
79
|
+
|
|
80
|
+
def __new__(mcs, name, bases, namespace, **kwargs):
|
|
81
|
+
cls = super().__new__(mcs, name, bases, namespace, **kwargs)
|
|
82
|
+
|
|
83
|
+
# Add __get_pydantic_core_schema__ to make open enums work correctly
|
|
84
|
+
# in union discrimination. In strict mode (used by Pydantic for unions),
|
|
85
|
+
# only known enum values match. In lax mode, unknown values are accepted.
|
|
86
|
+
def __get_pydantic_core_schema__(
|
|
87
|
+
cls_inner: Any, _source_type: Any, _handler: Any
|
|
88
|
+
) -> core_schema.CoreSchema:
|
|
89
|
+
# Create a validator that only accepts known enum values (for strict mode)
|
|
90
|
+
def validate_strict(v: Any) -> Any:
|
|
91
|
+
if isinstance(v, cls_inner):
|
|
92
|
+
return v
|
|
93
|
+
# Use the parent EnumMeta's __call__ which raises ValueError for unknown values
|
|
94
|
+
return enum.EnumMeta.__call__(cls_inner, v)
|
|
95
|
+
|
|
96
|
+
# Create a lax validator that accepts unknown values
|
|
97
|
+
def validate_lax(v: Any) -> Any:
|
|
98
|
+
if isinstance(v, cls_inner):
|
|
99
|
+
return v
|
|
100
|
+
try:
|
|
101
|
+
return enum.EnumMeta.__call__(cls_inner, v)
|
|
102
|
+
except ValueError:
|
|
103
|
+
# Return the raw value for unknown enum values
|
|
104
|
+
return v
|
|
105
|
+
|
|
106
|
+
# Determine the base type schema (str or int)
|
|
107
|
+
is_int_enum = False
|
|
108
|
+
for base in cls_inner.__mro__:
|
|
109
|
+
if base is int:
|
|
110
|
+
is_int_enum = True
|
|
111
|
+
break
|
|
112
|
+
if base is str:
|
|
113
|
+
break
|
|
114
|
+
|
|
115
|
+
base_schema = (
|
|
116
|
+
core_schema.int_schema()
|
|
117
|
+
if is_int_enum
|
|
118
|
+
else core_schema.str_schema()
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Use lax_or_strict_schema:
|
|
122
|
+
# - strict mode: only known enum values match (raises ValueError for unknown)
|
|
123
|
+
# - lax mode: accept any value, return enum member or raw value
|
|
124
|
+
return core_schema.lax_or_strict_schema(
|
|
125
|
+
lax_schema=core_schema.chain_schema(
|
|
126
|
+
[base_schema, core_schema.no_info_plain_validator_function(validate_lax)]
|
|
127
|
+
),
|
|
128
|
+
strict_schema=core_schema.chain_schema(
|
|
129
|
+
[base_schema, core_schema.no_info_plain_validator_function(validate_strict)]
|
|
130
|
+
),
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
setattr(cls, "__get_pydantic_core_schema__", classmethod(__get_pydantic_core_schema__))
|
|
134
|
+
return cls
|
dub/utils/forms.py
CHANGED
|
@@ -142,16 +142,21 @@ def serialize_multipart_form(
|
|
|
142
142
|
if field_metadata.file:
|
|
143
143
|
if isinstance(val, List):
|
|
144
144
|
# Handle array of files
|
|
145
|
+
array_field_name = f_name + "[]"
|
|
145
146
|
for file_obj in val:
|
|
146
147
|
if not _is_set(file_obj):
|
|
147
148
|
continue
|
|
148
|
-
|
|
149
|
-
file_name, content, content_type = _extract_file_properties(
|
|
149
|
+
|
|
150
|
+
file_name, content, content_type = _extract_file_properties(
|
|
151
|
+
file_obj
|
|
152
|
+
)
|
|
150
153
|
|
|
151
154
|
if content_type is not None:
|
|
152
|
-
files.append(
|
|
155
|
+
files.append(
|
|
156
|
+
(array_field_name, (file_name, content, content_type))
|
|
157
|
+
)
|
|
153
158
|
else:
|
|
154
|
-
files.append((
|
|
159
|
+
files.append((array_field_name, (file_name, content)))
|
|
155
160
|
else:
|
|
156
161
|
# Handle single file
|
|
157
162
|
file_name, content, content_type = _extract_file_properties(val)
|
|
@@ -161,11 +166,16 @@ def serialize_multipart_form(
|
|
|
161
166
|
else:
|
|
162
167
|
files.append((f_name, (file_name, content)))
|
|
163
168
|
elif field_metadata.json:
|
|
164
|
-
files.append(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
+
files.append(
|
|
170
|
+
(
|
|
171
|
+
f_name,
|
|
172
|
+
(
|
|
173
|
+
None,
|
|
174
|
+
marshal_json(val, request_field_types[name]),
|
|
175
|
+
"application/json",
|
|
176
|
+
),
|
|
177
|
+
)
|
|
178
|
+
)
|
|
169
179
|
else:
|
|
170
180
|
if isinstance(val, List):
|
|
171
181
|
values = []
|
|
@@ -175,7 +185,8 @@ def serialize_multipart_form(
|
|
|
175
185
|
continue
|
|
176
186
|
values.append(_val_to_string(value))
|
|
177
187
|
|
|
178
|
-
|
|
188
|
+
array_field_name = f_name + "[]"
|
|
189
|
+
form[array_field_name] = values
|
|
179
190
|
else:
|
|
180
191
|
form[f_name] = _val_to_string(val)
|
|
181
192
|
return media_type, form, files
|
dub/utils/queryparams.py
CHANGED
|
@@ -27,12 +27,13 @@ from .forms import _populate_form
|
|
|
27
27
|
def get_query_params(
|
|
28
28
|
query_params: Any,
|
|
29
29
|
gbls: Optional[Any] = None,
|
|
30
|
+
allow_empty_value: Optional[List[str]] = None,
|
|
30
31
|
) -> Dict[str, List[str]]:
|
|
31
32
|
params: Dict[str, List[str]] = {}
|
|
32
33
|
|
|
33
|
-
globals_already_populated = _populate_query_params(query_params, gbls, params, [])
|
|
34
|
+
globals_already_populated = _populate_query_params(query_params, gbls, params, [], allow_empty_value)
|
|
34
35
|
if _is_set(gbls):
|
|
35
|
-
_populate_query_params(gbls, None, params, globals_already_populated)
|
|
36
|
+
_populate_query_params(gbls, None, params, globals_already_populated, allow_empty_value)
|
|
36
37
|
|
|
37
38
|
return params
|
|
38
39
|
|
|
@@ -42,6 +43,7 @@ def _populate_query_params(
|
|
|
42
43
|
gbls: Any,
|
|
43
44
|
query_param_values: Dict[str, List[str]],
|
|
44
45
|
skip_fields: List[str],
|
|
46
|
+
allow_empty_value: Optional[List[str]] = None,
|
|
45
47
|
) -> List[str]:
|
|
46
48
|
globals_already_populated: List[str] = []
|
|
47
49
|
|
|
@@ -69,6 +71,16 @@ def _populate_query_params(
|
|
|
69
71
|
globals_already_populated.append(name)
|
|
70
72
|
|
|
71
73
|
f_name = field.alias if field.alias is not None else name
|
|
74
|
+
|
|
75
|
+
allow_empty_set = set(allow_empty_value or [])
|
|
76
|
+
should_include_empty = f_name in allow_empty_set and (
|
|
77
|
+
value is None or value == [] or value == ""
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if should_include_empty:
|
|
81
|
+
query_param_values[f_name] = [""]
|
|
82
|
+
continue
|
|
83
|
+
|
|
72
84
|
serialization = metadata.serialization
|
|
73
85
|
if serialization is not None:
|
|
74
86
|
serialized_parms = _get_serialized_params(
|
dub/utils/requestbodies.py
CHANGED
|
@@ -44,15 +44,15 @@ def serialize_request_body(
|
|
|
44
44
|
|
|
45
45
|
serialized_request_body = SerializedRequestBody(media_type)
|
|
46
46
|
|
|
47
|
-
if re.match(r"(application|text)
|
|
47
|
+
if re.match(r"^(application|text)\/([^+]+\+)*json.*", media_type) is not None:
|
|
48
48
|
serialized_request_body.content = marshal_json(request_body, request_body_type)
|
|
49
|
-
elif re.match(r"multipart\/.*", media_type) is not None:
|
|
49
|
+
elif re.match(r"^multipart\/.*", media_type) is not None:
|
|
50
50
|
(
|
|
51
51
|
serialized_request_body.media_type,
|
|
52
52
|
serialized_request_body.data,
|
|
53
53
|
serialized_request_body.files,
|
|
54
54
|
) = serialize_multipart_form(media_type, request_body)
|
|
55
|
-
elif re.match(r"application\/x-www-form-urlencoded.*", media_type) is not None:
|
|
55
|
+
elif re.match(r"^application\/x-www-form-urlencoded.*", media_type) is not None:
|
|
56
56
|
serialized_request_body.data = serialize_form_data(request_body)
|
|
57
57
|
elif isinstance(request_body, (bytes, bytearray, io.BytesIO, io.BufferedReader)):
|
|
58
58
|
serialized_request_body.content = request_body
|
dub/utils/serializers.py
CHANGED
|
@@ -102,26 +102,6 @@ def validate_int(b):
|
|
|
102
102
|
return int(b)
|
|
103
103
|
|
|
104
104
|
|
|
105
|
-
def validate_open_enum(is_int: bool):
|
|
106
|
-
def validate(e):
|
|
107
|
-
if e is None:
|
|
108
|
-
return None
|
|
109
|
-
|
|
110
|
-
if isinstance(e, Unset):
|
|
111
|
-
return e
|
|
112
|
-
|
|
113
|
-
if is_int:
|
|
114
|
-
if not isinstance(e, int):
|
|
115
|
-
raise ValueError("Expected int")
|
|
116
|
-
else:
|
|
117
|
-
if not isinstance(e, str):
|
|
118
|
-
raise ValueError("Expected string")
|
|
119
|
-
|
|
120
|
-
return e
|
|
121
|
-
|
|
122
|
-
return validate
|
|
123
|
-
|
|
124
|
-
|
|
125
105
|
def validate_const(v):
|
|
126
106
|
def validate(c):
|
|
127
107
|
# Optional[T] is a Union[T, None]
|