jararaca 0.3.12a19__py3-none-any.whl → 0.3.12a21__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 jararaca might be problematic. Click here for more details.

@@ -48,6 +48,35 @@ def is_constant(name: str) -> bool:
48
48
  return CONSTANT_PATTERN.match(name) is not None
49
49
 
50
50
 
51
+ def unwrap_annotated_type(field_type: Any) -> tuple[Any, list[Any]]:
52
+ """
53
+ Recursively unwrap Annotated types to find the real underlying type.
54
+
55
+ Args:
56
+ field_type: The type to unwrap, which may be deeply nested Annotated types
57
+
58
+ Returns:
59
+ A tuple of (unwrapped_type, all_metadata) where:
60
+ - unwrapped_type is the final non-Annotated type
61
+ - all_metadata is a list of all metadata from all Annotated layers
62
+ """
63
+ all_metadata = []
64
+ current_type = field_type
65
+
66
+ while get_origin(current_type) == Annotated:
67
+ # Collect metadata from current layer
68
+ if hasattr(current_type, "__metadata__"):
69
+ all_metadata.extend(current_type.__metadata__)
70
+
71
+ # Move to the next inner type
72
+ if hasattr(current_type, "__args__") and len(current_type.__args__) > 0:
73
+ current_type = current_type.__args__[0]
74
+ else:
75
+ break
76
+
77
+ return current_type, all_metadata
78
+
79
+
51
80
  def is_upload_file_type(field_type: Any) -> bool:
52
81
  """
53
82
  Check if a type is UploadFile or a list/array of UploadFile.
@@ -110,7 +139,8 @@ def should_exclude_field(
110
139
 
111
140
  # Check for Annotated types with Field metadata
112
141
  if get_origin(field_type) == Annotated:
113
- for metadata in field_type.__metadata__:
142
+ unwrapped_type, all_metadata = unwrap_annotated_type(field_type)
143
+ for metadata in all_metadata:
114
144
  # Check if this is a Pydantic Field by looking for expected attributes
115
145
  if hasattr(metadata, "exclude") or hasattr(metadata, "alias"):
116
146
  # Check if Field has exclude=True
@@ -205,7 +235,8 @@ def has_default_value(
205
235
 
206
236
  # Check for Annotated types with Field metadata that have defaults
207
237
  if get_origin(field_type) == Annotated:
208
- for metadata in field_type.__metadata__:
238
+ unwrapped_type, all_metadata = unwrap_annotated_type(field_type)
239
+ for metadata in all_metadata:
209
240
  # Check if this is a Pydantic Field with a default
210
241
  if hasattr(metadata, "default") and hasattr(
211
242
  metadata, "exclude"
@@ -356,16 +387,18 @@ def get_field_type_for_ts(field_type: Any, context_suffix: str = "") -> Any:
356
387
  [get_field_type_for_ts(x, context_suffix) for x in field_type.__args__]
357
388
  )
358
389
  if (get_origin(field_type) == Annotated) and (len(field_type.__args__) > 0):
390
+ unwrapped_type, all_metadata = unwrap_annotated_type(field_type)
391
+
359
392
  if (
360
393
  plain_validator := next(
361
- (x for x in field_type.__metadata__ if isinstance(x, PlainValidator)),
394
+ (x for x in all_metadata if isinstance(x, PlainValidator)),
362
395
  None,
363
396
  )
364
397
  ) is not None:
365
398
  return get_field_type_for_ts(
366
399
  plain_validator.json_schema_input_type, context_suffix
367
400
  )
368
- return get_field_type_for_ts(field_type.__args__[0], context_suffix)
401
+ return get_field_type_for_ts(unwrapped_type, context_suffix)
369
402
  return "unknown"
370
403
 
371
404
 
@@ -652,17 +685,31 @@ import { HttpService, HttpBackend, HttpBackendRequest, ResponseType, createClass
652
685
  function makeFormData(data: Record<string, any>): FormData {
653
686
  const formData = new FormData();
654
687
  for (const key in data) {
655
- if (Array.isArray(data[key])) {
656
- data[key].forEach((item: any) => {
657
- formData.append(key, item);
658
- });
659
- } else {
660
- formData.append(key, data[key]);
688
+ const value = data[key];
689
+ for (const v of genFormDataValue(value)) {
690
+ formData.append(key, v);
661
691
  }
662
692
  }
663
693
  return formData;
664
694
  }
665
695
 
696
+ function* genFormDataValue(value: any): any {
697
+ if (Array.isArray(value)) {
698
+ // Stringify arrays as JSON
699
+ for (const item of value) {
700
+ // formData.append(`${key}`, item);
701
+ yield* genFormDataValue(item);
702
+ }
703
+ } else if (typeof value === "object" && value.constructor === Object) {
704
+ // Stringify plain objects as JSON
705
+ // formData.append(key, JSON.stringify(value));
706
+ yield JSON.stringify(value);
707
+ } else {
708
+ // For primitives (string, number, boolean), append as-is
709
+ yield value;
710
+ }
711
+ }
712
+
666
713
  export type WebSocketMessageMap = {
667
714
  %s
668
715
  }
@@ -974,15 +1021,16 @@ def extract_parameters(
974
1021
  if is_primitive(member):
975
1022
 
976
1023
  if get_origin(member) is Annotated:
1024
+ unwrapped_type, all_metadata = unwrap_annotated_type(member)
977
1025
  if (
978
1026
  plain_validator := next(
979
- (x for x in member.__metadata__ if isinstance(x, PlainValidator)),
1027
+ (x for x in all_metadata if isinstance(x, PlainValidator)),
980
1028
  None,
981
1029
  )
982
1030
  ) is not None:
983
1031
  mapped_types.add(plain_validator.json_schema_input_type)
984
1032
  return parameters_list, mapped_types
985
- return extract_parameters(member.__args__[0], controller, mapping)
1033
+ return extract_parameters(unwrapped_type, controller, mapping)
986
1034
  return parameters_list, mapped_types
987
1035
 
988
1036
  if hasattr(member, "__bases__"):
@@ -1002,8 +1050,21 @@ def extract_parameters(
1002
1050
  continue
1003
1051
 
1004
1052
  if get_origin(parameter_type) == Annotated:
1005
- annotated_type_hook = parameter_type.__metadata__[0]
1006
- annotated_type = parameter_type.__args__[0]
1053
+ unwrapped_type, all_metadata = unwrap_annotated_type(parameter_type)
1054
+ # Look for FastAPI parameter annotations in all metadata layers
1055
+ annotated_type_hook = None
1056
+ for metadata in all_metadata:
1057
+ if isinstance(
1058
+ metadata, (Header, Cookie, Form, Body, Query, Path, Depends)
1059
+ ):
1060
+ annotated_type_hook = metadata
1061
+ break
1062
+
1063
+ if annotated_type_hook is None and all_metadata:
1064
+ # Fallback to first metadata if no FastAPI annotation found
1065
+ annotated_type_hook = all_metadata[0]
1066
+
1067
+ annotated_type = unwrapped_type
1007
1068
  if isinstance(annotated_type_hook, Header):
1008
1069
  mapped_types.add(str)
1009
1070
  parameters_list.append(
@@ -1270,21 +1331,22 @@ def extract_parameters(
1270
1331
  for _, parameter_type in parameter_members.items():
1271
1332
  if is_primitive(parameter_type.annotation):
1272
1333
  if get_origin(parameter_type.annotation) is not None:
1273
- if (
1274
- get_origin(parameter_type.annotation) == Annotated
1275
- and (
1276
- plain_validator := next(
1277
- (
1278
- x
1279
- for x in parameter_type.annotation.__metadata__
1280
- if isinstance(x, PlainValidator)
1281
- ),
1282
- None,
1283
- )
1334
+ if get_origin(parameter_type.annotation) == Annotated:
1335
+ unwrapped_type, all_metadata = unwrap_annotated_type(
1336
+ parameter_type.annotation
1337
+ )
1338
+ plain_validator = next(
1339
+ (
1340
+ x
1341
+ for x in all_metadata
1342
+ if isinstance(x, PlainValidator)
1343
+ ),
1344
+ None,
1284
1345
  )
1285
- is not None
1286
- ):
1287
- mapped_types.add(plain_validator.json_schema_input_type)
1346
+ if plain_validator is not None:
1347
+ mapped_types.add(
1348
+ plain_validator.json_schema_input_type
1349
+ )
1288
1350
  else:
1289
1351
  args = parameter_type.annotation.__args__
1290
1352
  mapped_types.update(args)
@@ -1315,22 +1377,15 @@ def extract_all_envolved_types(field_type: Any) -> set[Any]:
1315
1377
 
1316
1378
  if is_primitive(field_type):
1317
1379
  if get_origin(field_type) is not None:
1318
- if (
1319
- get_origin(field_type) == Annotated
1320
- and (
1321
- plain_validator := next(
1322
- (
1323
- x
1324
- for x in field_type.__metadata__
1325
- if isinstance(x, PlainValidator)
1326
- ),
1327
- None,
1328
- )
1380
+ if get_origin(field_type) == Annotated:
1381
+ unwrapped_type, all_metadata = unwrap_annotated_type(field_type)
1382
+ plain_validator = next(
1383
+ (x for x in all_metadata if isinstance(x, PlainValidator)),
1384
+ None,
1329
1385
  )
1330
- is not None
1331
- ):
1332
- mapped_types.add(plain_validator.json_schema_input_type)
1333
- return mapped_types
1386
+ if plain_validator is not None:
1387
+ mapped_types.add(plain_validator.json_schema_input_type)
1388
+ return mapped_types
1334
1389
  else:
1335
1390
  mapped_types.update(
1336
1391
  *[extract_all_envolved_types(arg) for arg in field_type.__args__]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jararaca
3
- Version: 0.3.12a19
3
+ Version: 0.3.12a21
4
4
  Summary: A simple and fast API framework for Python
5
5
  Home-page: https://github.com/LuscasLeo/jararaca
6
6
  Author: Lucas S
@@ -1,6 +1,6 @@
1
1
  LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
2
2
  README.md,sha256=2qMM__t_MoLKZr4IY9tXjo-Jn6LKjuHMb1qbyXpgL08,3401
3
- pyproject.toml,sha256=mgJOhSQjMq5tiTypMWYNHonlLtptX67W82wrg7OUiFg,2041
3
+ pyproject.toml,sha256=FFIzsD3RSowe1XEnXO2Uwa-9db12IWVmktZG9IhS-p4,2041
4
4
  jararaca/__init__.py,sha256=vK3zyIVLckwZgj1FPX6jzSbzaSWmSy3wQ2KMwmpJnmg,22046
5
5
  jararaca/__main__.py,sha256=-O3vsB5lHdqNFjUtoELDF81IYFtR-DSiiFMzRaiSsv4,67
6
6
  jararaca/broker_backend/__init__.py,sha256=GzEIuHR1xzgCJD4FE3harNjoaYzxHMHoEL0_clUaC-k,3528
@@ -70,12 +70,12 @@ jararaca/tools/app_config/decorators.py,sha256=-ckkMZ1dswOmECdo1rFrZ15UAku--txaN
70
70
  jararaca/tools/app_config/interceptor.py,sha256=HV8h4AxqUc_ACs5do4BSVlyxlRXzx7HqJtoVO9tfRnQ,2611
71
71
  jararaca/tools/typescript/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
72
  jararaca/tools/typescript/decorators.py,sha256=y1zBq8mBZ8CBXlZ0nKy2RyIgCvP9kp4elACbaC6dptQ,2946
73
- jararaca/tools/typescript/interface_parser.py,sha256=dkM3Nsab_1HDRY_clC6LcZLtDXFHpAqNdcqIC_MzALc,51753
73
+ jararaca/tools/typescript/interface_parser.py,sha256=hJzP-XCwVQ7kjJHBj9VGq8mrSdNQjO0VlYFIPVf4ukI,53997
74
74
  jararaca/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
75
  jararaca/utils/rabbitmq_utils.py,sha256=ytdAFUyv-OBkaVnxezuJaJoLrmN7giZgtKeet_IsMBs,10918
76
76
  jararaca/utils/retry.py,sha256=DzPX_fXUvTqej6BQ8Mt2dvLo9nNlTBm7Kx2pFZ26P2Q,4668
77
- jararaca-0.3.12a19.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
78
- jararaca-0.3.12a19.dist-info/METADATA,sha256=lpSsuVzfv-LNkPBbg-eFlR-E2PcsCzlNXl0da8gQbQk,4996
79
- jararaca-0.3.12a19.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
80
- jararaca-0.3.12a19.dist-info/entry_points.txt,sha256=WIh3aIvz8LwUJZIDfs4EeH3VoFyCGEk7cWJurW38q0I,45
81
- jararaca-0.3.12a19.dist-info/RECORD,,
77
+ jararaca-0.3.12a21.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
78
+ jararaca-0.3.12a21.dist-info/METADATA,sha256=XM64PPm552_itonm5kavo5oZfnlUA81M8IaBAd4su9U,4996
79
+ jararaca-0.3.12a21.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
80
+ jararaca-0.3.12a21.dist-info/entry_points.txt,sha256=WIh3aIvz8LwUJZIDfs4EeH3VoFyCGEk7cWJurW38q0I,45
81
+ jararaca-0.3.12a21.dist-info/RECORD,,
pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "jararaca"
3
- version = "0.3.12a19"
3
+ version = "0.3.12a21"
4
4
  description = "A simple and fast API framework for Python"
5
5
  authors = ["Lucas S <me@luscasleo.dev>"]
6
6
  readme = "README.md"