UncountablePythonSDK 0.0.26__py3-none-any.whl → 0.0.28__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 UncountablePythonSDK might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.26
3
+ Version: 0.0.28
4
4
  Summary: Uncountable SDK
5
5
  Project-URL: Homepage, https://github.com/uncountableinc/uncountable-python-sdk
6
6
  Project-URL: Repository, https://github.com/uncountableinc/uncountable-python-sdk.git
@@ -16,21 +16,21 @@ Classifier: Topic :: Utilities
16
16
  Classifier: Typing :: Typed
17
17
  Requires-Python: >=3.11
18
18
  Description-Content-Type: text/markdown
19
- Requires-Dist: aiotus ==0.1.15
20
- Requires-Dist: aiohttp ==3.9.5
21
- Requires-Dist: requests ==2.31.0
22
- Requires-Dist: SQLAlchemy ==1.4.52
23
- Requires-Dist: APScheduler ==3.10.4
24
- Requires-Dist: python-dateutil ==2.9.0.post0
25
- Requires-Dist: shelljob ==0.6.3
26
- Requires-Dist: PyYAML ==6.0.1
19
+ Requires-Dist: aiotus ==0.*
20
+ Requires-Dist: aiohttp ==3.*
21
+ Requires-Dist: requests ==2.*
22
+ Requires-Dist: SQLAlchemy ==1.4.*
23
+ Requires-Dist: APScheduler ==3.*
24
+ Requires-Dist: python-dateutil ==2.*
25
+ Requires-Dist: shelljob ==0.*
26
+ Requires-Dist: PyYAML ==6.*
27
27
  Provides-Extra: test
28
- Requires-Dist: mypy >=1.8.1 ; extra == 'test'
29
- Requires-Dist: ruff >=0.2.1 ; extra == 'test'
30
- Requires-Dist: pytest >=7.4.3 ; extra == 'test'
31
- Requires-Dist: coverage[toml] >=6.5.0 ; extra == 'test'
32
- Requires-Dist: pytest-cov >=4.1.0 ; extra == 'test'
33
- Requires-Dist: pytest-xdist >=3.5.0 ; extra == 'test'
28
+ Requires-Dist: mypy ==1.* ; extra == 'test'
29
+ Requires-Dist: ruff ==0.* ; extra == 'test'
30
+ Requires-Dist: pytest ==7.* ; extra == 'test'
31
+ Requires-Dist: coverage[toml] ==6.* ; extra == 'test'
32
+ Requires-Dist: pytest-cov ==4.* ; extra == 'test'
33
+ Requires-Dist: pytest-xdist ==3.* ; extra == 'test'
34
34
 
35
35
  # Uncountable Python SDK
36
36
 
@@ -35,12 +35,12 @@ pkgs/strenum_compat/__init__.py,sha256=wXRFeNvBm8RU6dy1PFJ5sRLgUIEeH_DVR95Sv5qpG
35
35
  pkgs/strenum_compat/strenum_compat.py,sha256=uOUAgpYTjHs1MX8dG81jRlyTkt3KNbkV_25zp7xTX2s,36
36
36
  pkgs/type_spec/__init__.py,sha256=h5DmJTca4QVV10sZR1x0-MlkZfuGYDfapR3zHvXfzto,19
37
37
  pkgs/type_spec/__main__.py,sha256=5bJaX9Y_-FavP0qwzhk-z-V97UY7uaezJTa1zhO_HHQ,1048
38
- pkgs/type_spec/builder.py,sha256=S7lZCbGbeQ9cUQHnhY9vvpgFUQj8DjsOaNBVqRUff6Y,43253
38
+ pkgs/type_spec/builder.py,sha256=1C_ELB7KfK118QxZDLLc_Uf_nh5TAg96ilpOCfEQuN4,43685
39
39
  pkgs/type_spec/config.py,sha256=INfEiDcUsZFUKasHprsE6i33siPB0RnfmTKOsWcGnQ8,5043
40
40
  pkgs/type_spec/emit_io_ts.py,sha256=Ghd8XYqyNYldHQDepwa9GLfHXcoi48ztBw84K28ETic,5707
41
- pkgs/type_spec/emit_open_api.py,sha256=nDUlVSmzqc1GkbyND9rbeM2AHOO-mbtzRmdOqA6KKXE,23821
41
+ pkgs/type_spec/emit_open_api.py,sha256=rAxfPVsqJU7ass76dPhImgPao6AW6xyz-rMaQDhSp1I,23822
42
42
  pkgs/type_spec/emit_open_api_util.py,sha256=XAA6zH59aZWLVl0BvKAICXXl4sdBqx01QAtv5oB0bMI,2266
43
- pkgs/type_spec/emit_python.py,sha256=aGPnp86DZN0N7c5eiBHVAT_smDf1uCLmRldDhxmWx9g,42673
43
+ pkgs/type_spec/emit_python.py,sha256=1Ei2PaqRs1qeQj5LWYfcRUHyzEoMI3DhDzomXmhX_-A,44139
44
44
  pkgs/type_spec/emit_typescript.py,sha256=4hpCJwiDf-v8LJaNFVfFtf8zvtG73YNPFwwa_5NuffI,17729
45
45
  pkgs/type_spec/emit_typescript_util.py,sha256=93FzJnpYse4PKFzgdw4DGV4zFTi5tF4WR-CIi7cW498,873
46
46
  pkgs/type_spec/load_types.py,sha256=xEHwdB_miR3vNs161Oy1luafE0VC-yk9-utAyCJmbEo,3629
@@ -83,7 +83,7 @@ type_spec/external/api/inputs/set_input_attribute_values.yaml,sha256=RpOtVIWBlOp
83
83
  type_spec/external/api/inputs/set_input_category.yaml,sha256=2zcDYw_WzBfzFNkhfDDer45MgRxGnzOBLFicDWrvN80,676
84
84
  type_spec/external/api/inputs/set_input_subcategories.yaml,sha256=xbydzqVHIktslueosU3dJxdAu4a8uc5jQc5Cccdw7i8,682
85
85
  type_spec/external/api/material_families/update_entity_material_families.yaml,sha256=2WjU7XycTHEaZ2YA_FhwzndVN-PqWsyPCJhBE1WRKvQ,1231
86
- type_spec/external/api/outputs/get_output_data.yaml,sha256=N884q2C1xLQfFxsmjKr8MJ23IU4q2ORCVJh5y5h6ePE,3555
86
+ type_spec/external/api/outputs/get_output_data.yaml,sha256=D-xr8u1SfYUGtXG1fcAi8V44d5rVg48LtOK5BhCDXr4,3556
87
87
  type_spec/external/api/outputs/get_output_names.yaml,sha256=p-3ubOjEFNjV746zpAkXurCu0yVUvonDssJKk48ueVM,1404
88
88
  type_spec/external/api/outputs/resolve_output_conditions.yaml,sha256=lGrG6XPGiQtHx24GccPcO18xxAoMynTSC_2WwxCjFrc,1640
89
89
  type_spec/external/api/permissions/set_core_permissions.yaml,sha256=SDM_3FE-ur00dv6Na9HlaJBIvSPgnfqRieGDKnBR1UY,1632
@@ -103,7 +103,7 @@ type_spec/external/api/recipes/get_recipe_calculations.yaml,sha256=ZE7PzfWrjS7Ti
103
103
  type_spec/external/api/recipes/get_recipe_links.yaml,sha256=Vwm0OVWl3VvDaI7chY_oZQqD8xZ1u09iFWKkZKn1ITo,766
104
104
  type_spec/external/api/recipes/get_recipe_names.yaml,sha256=4tqcVj-xLeEu0lhdm8NpLYmAvfkmq08GZ0Mr59I5nLI,896
105
105
  type_spec/external/api/recipes/get_recipe_output_metadata.yaml,sha256=YImW94JXVKR6Wz_7R7sRbhD9Ul51Ba-j-x9vJB__AAU,1216
106
- type_spec/external/api/recipes/get_recipes_data.yaml,sha256=NQTI4k7IgtXMfcOxcKjPzrvHGkPGuiLQj7GZuHqumUI,11608
106
+ type_spec/external/api/recipes/get_recipes_data.yaml,sha256=CGfmb-mxpVmS68XrVkGEaRJmA6ZtgQhulmxlXya9TyU,11609
107
107
  type_spec/external/api/recipes/set_recipe_inputs.yaml,sha256=MvnHuzI9JKfkYZb-pC4jeE7FRpGeacJKXd5_GImsDiY,1747
108
108
  type_spec/external/api/recipes/set_recipe_metadata.yaml,sha256=5N9AIY9x3pZhDXyzpM__e7pyKNTI2RS7OeBmwmj5nEs,585
109
109
  type_spec/external/api/recipes/set_recipe_outputs.yaml,sha256=Oe8XGYXbPNmrbEDXk3qucfS1L3P9TnXI5cxaNAl6x5A,1875
@@ -114,9 +114,9 @@ uncountable/__init__.py,sha256=281cC2hs8pbrD0jVKMol-tbWSh7Zcsc8oRT42dKteyE,102
114
114
  uncountable/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
115
115
  uncountable/core/__init__.py,sha256=J0CeeztqyJe7klvHM-8fwSivN1sud6xZThOdaThnQrU,314
116
116
  uncountable/core/async_batch.py,sha256=0cRmCr6Z9sNxZyfY9Dl8wlCA4anISVZuHGgBegHhUbc,749
117
- uncountable/core/client.py,sha256=cP6yEHv5KGE2NJn0BAQh470mirBfITMLsfEs-zj-6Ys,9024
118
- uncountable/core/file_upload.py,sha256=zTpAFSd7_-TmEVWxOn1rDznyWE6_AdZyuDQC3LP34iI,2667
119
- uncountable/core/types.py,sha256=RaNVuUPpcMBCfk-stS4Jh-9WBFzKK6_cVgRfPv7Dz6g,280
117
+ uncountable/core/client.py,sha256=J_J9zEfSpWRx4RBSl2gIDqtUpC7ca1hpEvbHVfe7_jQ,9045
118
+ uncountable/core/file_upload.py,sha256=YWOay69i_-sNGBNnwzKb3bY3OMaV4lRsdVZZK-ScXVc,2829
119
+ uncountable/core/types.py,sha256=zM_FqVT41qqZAhXxKSK_kQccArfw6B_p2qMYBRKJHqE,332
120
120
  uncountable/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
121
121
  uncountable/integration/construct_client.py,sha256=r6M5pnIO0fKcjf5d_AREPtWZ6AkWgcjkdu_jHQEYlT8,1084
122
122
  uncountable/integration/cron.py,sha256=TIPqMPMSMtMJTu4aXwLf6QY-OLrpmyITLDp48UIr4Ok,919
@@ -193,7 +193,7 @@ uncountable/types/api/inputs/set_input_subcategories.py,sha256=hRS1FcFWPaenO_08I
193
193
  uncountable/types/api/material_families/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
194
194
  uncountable/types/api/material_families/update_entity_material_families.py,sha256=h-vkua57yCNSO6P1akIxmmaFdwzOXPxm2s3Xt6x1c7c,1396
195
195
  uncountable/types/api/outputs/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
196
- uncountable/types/api/outputs/get_output_data.py,sha256=CpYlXNGWWNTiMgDPBRwucSseSrX4gnLuLIp2ljiONrI,2216
196
+ uncountable/types/api/outputs/get_output_data.py,sha256=vlWDHhMUVMoHZSdN778-puOvmu7uGlDE3cQwKfYd1iI,2240
197
197
  uncountable/types/api/outputs/get_output_names.py,sha256=Id_ApombSzzFdq5rD4uOfWIKzthic6KBAeyqcrhsx18,1086
198
198
  uncountable/types/api/outputs/resolve_output_conditions.py,sha256=XZqUseXcGhApHmPm-2u7a37Y4blLRxoPoLhvYlBfCpI,1799
199
199
  uncountable/types/api/permissions/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
@@ -218,7 +218,7 @@ uncountable/types/api/recipes/get_recipe_calculations.py,sha256=eQmkdZzCEuq8S2f_
218
218
  uncountable/types/api/recipes/get_recipe_links.py,sha256=hk5dfQjv7yU2r-S9b8vwWEJLPHqU0-M6SFiTLMR3fVk,985
219
219
  uncountable/types/api/recipes/get_recipe_names.py,sha256=uCpXZq5oWjr9a_Vf-yYPaVS72XOlLHgAlju6KHeQ3UA,986
220
220
  uncountable/types/api/recipes/get_recipe_output_metadata.py,sha256=L9s2ykPP4pd02Pc98LDisY8bgV8CToS6t6fXKTWqGRw,1464
221
- uncountable/types/api/recipes/get_recipes_data.py,sha256=wAmS28Nmc_tlP72XgrFMaj1y_yhvfgYbGw55wwERG_w,5388
221
+ uncountable/types/api/recipes/get_recipes_data.py,sha256=1j5ivENQr-EIvO0iW7-WoOsl59AA09S455etZtGKymk,5412
222
222
  uncountable/types/api/recipes/set_recipe_inputs.py,sha256=lFVfv-o_O5wHuMZdH63qlG4exFTlJM078oSAtb3XNxA,1426
223
223
  uncountable/types/api/recipes/set_recipe_metadata.py,sha256=Ba6ttd1JuS_Ypt-KpckSviWtOcQ-OTdTEJiaSYyoQL8,933
224
224
  uncountable/types/api/recipes/set_recipe_outputs.py,sha256=QYq39TNchQ80ET1C77OE9fwhbu_HmIoEDmrQJHkkCu0,1609
@@ -226,7 +226,7 @@ uncountable/types/api/recipes/set_recipe_tags.py,sha256=U710hgq9-t6QZGRB-ZGHskpt
226
226
  uncountable/types/api/recipes/unarchive_recipes.py,sha256=WcwFYbBsX2SKXnoBQ8locnRn7Bj1rHdtrURQVOfqgfU,814
227
227
  uncountable/types/api/triggers/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
228
228
  uncountable/types/api/triggers/run_trigger.py,sha256=9m9M8-nlGB_sAU2Qm2lWugp4h4Osqj6QpjNfU8osd1U,901
229
- UncountablePythonSDK-0.0.26.dist-info/METADATA,sha256=4LIsxPuj2u8AZ23XHXjF3L1mQdcVsa_renQYEwZhNJM,1613
230
- UncountablePythonSDK-0.0.26.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
231
- UncountablePythonSDK-0.0.26.dist-info/top_level.txt,sha256=HaMiBnH1wA7SG9-RVHIJPBH3l8X5gee2jUf-77Nz-Dk,41
232
- UncountablePythonSDK-0.0.26.dist-info/RECORD,,
229
+ UncountablePythonSDK-0.0.28.dist-info/METADATA,sha256=vbIveUXQ9GU38L6rahX-euZfbzPRvszGGh-gZ0i_0zQ,1577
230
+ UncountablePythonSDK-0.0.28.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
231
+ UncountablePythonSDK-0.0.28.dist-info/top_level.txt,sha256=HaMiBnH1wA7SG9-RVHIJPBH3l8X5gee2jUf-77Nz-Dk,41
232
+ UncountablePythonSDK-0.0.28.dist-info/RECORD,,
pkgs/type_spec/builder.py CHANGED
@@ -744,6 +744,8 @@ class SpecEndpoint:
744
744
  result_type: ResultType = ResultType.json
745
745
  has_attachment: bool = False
746
746
  desc: str | None = None
747
+ account_type: str | None
748
+ route_group: str | None
747
749
 
748
750
  is_external: bool = False
749
751
 
@@ -767,6 +769,8 @@ class SpecEndpoint:
767
769
  "deprecated",
768
770
  "result_type",
769
771
  "has_attachment",
772
+ "account_type",
773
+ "route_group",
770
774
  ],
771
775
  )
772
776
  self.method = RouteMethod(data["method"])
@@ -787,6 +791,14 @@ class SpecEndpoint:
787
791
  assert isinstance(is_sdk, bool)
788
792
  self.is_sdk = is_sdk
789
793
 
794
+ route_group = data.get("route_group")
795
+ assert route_group is None or isinstance(route_group, str)
796
+ self.route_group = route_group
797
+
798
+ account_type = data.get("account_type")
799
+ assert account_type is None or isinstance(account_type, str)
800
+ self.account_type = account_type
801
+
790
802
  is_beta = data.get("is_beta", False)
791
803
  assert isinstance(is_beta, bool)
792
804
  self.is_beta = is_beta
@@ -63,7 +63,7 @@ base_name_map = {
63
63
  def _rewrite_with_notice(
64
64
  file_path: str, file_content: str, *, notice: str = MODIFY_NOTICE
65
65
  ) -> bool:
66
- pattern = re.compile("^\S", re.MULTILINE)
66
+ pattern = re.compile(r"^\S", re.MULTILINE)
67
67
 
68
68
  file_lines = file_content.split("\n")
69
69
  comment_lines = []
@@ -1101,7 +1101,7 @@ def _emit_api_argument_lookup(
1101
1101
  for endpoint_root in builder.api_endpoints:
1102
1102
  routes_output = config.routes_output[endpoint_root]
1103
1103
 
1104
- imports = []
1104
+ imports = ["import typing", "from dataclasses import dataclass"]
1105
1105
  mappings = []
1106
1106
  for namespace in sorted(
1107
1107
  builder.namespaces.values(),
@@ -1121,7 +1121,28 @@ def _emit_api_argument_lookup(
1121
1121
  import_alias = "_".join(namespace.path[1:])
1122
1122
  api_import = f"{config.types_package}.{'.'.join(namespace.path)}"
1123
1123
  imports.append(f"import {api_import} as {import_alias}")
1124
- mappings.append(f"{import_alias}.ENDPOINT_PATH: {import_alias}.Arguments")
1124
+
1125
+ route_group = (
1126
+ f'"{endpoint.route_group}"'
1127
+ if endpoint.route_group is not None
1128
+ else "None"
1129
+ )
1130
+ account_type = (
1131
+ f'"{endpoint.account_type}"'
1132
+ if endpoint.account_type is not None
1133
+ else "None"
1134
+ )
1135
+
1136
+ mapping = f"{INDENT}ApiEndpointKey(route={import_alias}.ENDPOINT_PATH, method={import_alias}.ENDPOINT_METHOD): ApiEndpointSpec(\n"
1137
+ mapping += f"{INDENT}{INDENT}arguments_type={import_alias}.Arguments,\n"
1138
+ mapping += f"{INDENT}{INDENT}data_type={import_alias}.Data,\n"
1139
+ mapping += f"{INDENT}{INDENT}route_group={route_group},\n"
1140
+ mapping += f"{INDENT}{INDENT}account_type={account_type},\n"
1141
+ mapping += f"{INDENT}{INDENT}route={import_alias}.ENDPOINT_PATH,\n"
1142
+ mapping += f'{INDENT}{INDENT}handler="{endpoint.function}",\n'
1143
+ mapping += f"{INDENT}{INDENT}method={import_alias}.ENDPOINT_METHOD,\n"
1144
+ mapping += f"{INDENT})"
1145
+ mappings.append(mapping)
1125
1146
 
1126
1147
  argument_lookup_out = io.StringIO()
1127
1148
  argument_lookup_out.write(MODIFY_NOTICE)
@@ -1129,8 +1150,29 @@ def _emit_api_argument_lookup(
1129
1150
  argument_lookup_out.write(
1130
1151
  f"""{LINE_BREAK.join(imports)}
1131
1152
 
1132
- {API_ARGUMENTS_NAME} = {{
1133
- {f",{LINE_BREAK}{INDENT}".join(mappings)},
1153
+ AT = typing.TypeVar("AT")
1154
+ DT = typing.TypeVar("DT")
1155
+
1156
+
1157
+ @dataclass(kw_only=True, frozen=True)
1158
+ class ApiEndpointKey:
1159
+ method: str
1160
+ route: str
1161
+
1162
+
1163
+ @dataclass(kw_only=True)
1164
+ class ApiEndpointSpec(typing.Generic[AT, DT]):
1165
+ route: str
1166
+ arguments_type: type[AT]
1167
+ data_type: type[DT]
1168
+ route_group: str | None
1169
+ account_type: str | None
1170
+ handler: str
1171
+ method: str
1172
+
1173
+
1174
+ {API_ARGUMENTS_NAME}: dict[ApiEndpointKey, ApiEndpointSpec] = {{
1175
+ {f",{LINE_BREAK}".join(mappings)},
1134
1176
  }}
1135
1177
 
1136
1178
  __all__ = ["{API_ARGUMENTS_NAME}"]
@@ -27,7 +27,7 @@ OutputAttrVal:
27
27
  attribute_id:
28
28
  type: ObjectId
29
29
  desc: "The unique integer ID for the output attribute value. Used for joining and identification elsewhere."
30
- quantity_dec:
30
+ quantity_dec?:
31
31
  type: Decimal
32
32
  desc: "The value for the attribute, if it is of numeric type"
33
33
  quantity_json:
@@ -98,7 +98,7 @@ RecipeInput:
98
98
  curve_id:
99
99
  type: Optional<ObjectId>
100
100
  desc: "The id of the curve associated with the input if the input is of curve type."
101
- actual_quantity_dec:
101
+ actual_quantity_dec?:
102
102
  type: Decimal
103
103
  desc: "The actual quantity of the input if it is numeric or recipe type. If this is filled in, actual_quantity_json will not be filled in"
104
104
  actual_quantity_json:
@@ -15,7 +15,7 @@ from pkgs.serialization_util.serialization_helpers import JsonValue
15
15
  from uncountable.types.client_base import APIRequest, ClientMethods
16
16
 
17
17
  from .file_upload import FileUpload, FileUploader, UploadedFile
18
- from .types import AuthDetails, AuthDetailsApiKey, AuthDetailsOAuth
18
+ from .types import AuthDetailsAll, AuthDetailsApiKey, AuthDetailsOAuth
19
19
 
20
20
  DT = typing.TypeVar("DT")
21
21
 
@@ -129,7 +129,7 @@ oauth_bearer_token_data_parser = CachedParser(GetOauthBearerTokenData)
129
129
 
130
130
  class Client(ClientMethods):
131
131
  _parser_map: dict[type, CachedParser] = {}
132
- _auth_details: AuthDetails
132
+ _auth_details: AuthDetailsAll
133
133
  _base_url: str
134
134
  _file_uploader: FileUploader
135
135
  _cfg: ClientConfig
@@ -139,7 +139,7 @@ class Client(ClientMethods):
139
139
  self,
140
140
  *,
141
141
  base_url: str,
142
- auth_details: AuthDetails,
142
+ auth_details: AuthDetailsAll,
143
143
  config: ClientConfig | None = None,
144
144
  ):
145
145
  self._auth_details = auth_details
@@ -189,8 +189,8 @@ class Client(ClientMethods):
189
189
  try:
190
190
  data = response_data["data"]
191
191
  return cached_parser.parse_api(data)
192
- except ValueError | JSONDecodeError | KeyError:
193
- raise SDKError("unable to process response")
192
+ except (ValueError, JSONDecodeError, KeyError) as e:
193
+ raise SDKError("unable to process response") from e
194
194
 
195
195
  def _get_cached_parser(self, data_type: type[DT]) -> CachedParser[DT]:
196
196
  if data_type not in self._parser_map:
@@ -4,12 +4,12 @@ from dataclasses import dataclass
4
4
  from enum import StrEnum
5
5
  from io import BytesIO
6
6
  from pathlib import Path
7
- from typing import Generator, Literal, Self
7
+ from typing import Generator, Self
8
8
 
9
9
  import aiohttp
10
10
  import aiotus
11
11
 
12
- from .types import AuthDetails
12
+ from .types import AuthDetailsAll, AuthDetailsApiKey
13
13
 
14
14
  _CHUNK_SIZE = 5 * 1024 * 1024 # s3 requires 5MiB minimum
15
15
 
@@ -56,15 +56,18 @@ class UploadFailed(Exception):
56
56
 
57
57
 
58
58
  class FileUploader:
59
- _auth_details: AuthDetails
59
+ _auth_details: AuthDetailsAll
60
60
  _base_url: str
61
61
 
62
- def __init__(self: Self, base_url: str, auth_details: AuthDetails) -> None:
62
+ def __init__(self: Self, base_url: str, auth_details: AuthDetailsAll) -> None:
63
63
  self._base_url = base_url
64
64
  self._auth_details = auth_details
65
65
 
66
66
  async def _upload_file(self: Self, file_upload: FileUpload) -> UploadedFile:
67
67
  creation_url = f"{self._base_url}/api/external/file_upload/files"
68
+ if not isinstance(self._auth_details, AuthDetailsApiKey):
69
+ raise NotImplementedError("Unsupported authentication method.")
70
+
68
71
  auth = aiohttp.BasicAuth(
69
72
  self._auth_details.api_id, self._auth_details.api_secret_key
70
73
  )
uncountable/core/types.py CHANGED
@@ -13,4 +13,5 @@ class AuthDetailsOAuth:
13
13
  scope: str = "unc.rnd"
14
14
 
15
15
 
16
- AuthDetails = AuthDetailsApiKey | AuthDetailsOAuth
16
+ AuthDetails = AuthDetailsApiKey # Legacy Mapping
17
+ AuthDetailsAll = AuthDetailsApiKey | AuthDetailsOAuth
@@ -44,8 +44,8 @@ class Arguments:
44
44
  @dataclass(kw_only=True)
45
45
  class OutputAttrVal:
46
46
  attribute_id: base_t.ObjectId
47
- quantity_dec: Decimal
48
47
  quantity_json: base_t.JsonValue
48
+ quantity_dec: typing.Optional[Decimal] = None
49
49
 
50
50
 
51
51
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -97,10 +97,10 @@ class RecipeInput:
97
97
  quantity_dec: Decimal
98
98
  quantity_json: base_t.JsonValue
99
99
  curve_id: typing.Optional[base_t.ObjectId]
100
- actual_quantity_dec: Decimal
101
100
  actual_quantity_json: base_t.JsonValue
102
101
  input_type: str
103
102
  behavior: str
103
+ actual_quantity_dec: typing.Optional[Decimal] = None
104
104
 
105
105
 
106
106
  # DO NOT MODIFY -- This file is generated by type_spec