replit-river 0.17.12__py3-none-any.whl → 0.17.14__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.
@@ -101,6 +101,8 @@ class RiverConcreteType(BaseModel):
101
101
  items: "RiverType | None" = Field(default=None)
102
102
  const: str | int | None = Field(default=None)
103
103
  patternProperties: dict[str, "RiverType"] = Field(default_factory=lambda: dict())
104
+ id_: str | None = Field(default=None, alias="$id")
105
+ ref: str | None = Field(default=None, alias="$ref")
104
106
 
105
107
 
106
108
  class RiverUnionType(BaseModel):
@@ -158,7 +160,12 @@ def encode_type(
158
160
  base_model: str,
159
161
  in_module: list[ModuleName],
160
162
  permit_unknown_members: bool,
163
+ type_registry: dict[str, TypeName] | None = None,
161
164
  ) -> tuple[TypeExpression, list[ModuleName], list[FileContents], set[TypeName]]:
165
+ # Registry to track $id -> TypeName mappings for resolving $ref
166
+ if type_registry is None:
167
+ type_registry = {}
168
+
162
169
  def _make_open_union_type_expr(one_of: list[TypeExpression]) -> OpenUnionTypeExpr:
163
170
  if base_model == "RiverError":
164
171
  return OpenUnionTypeExpr(
@@ -175,6 +182,17 @@ def encode_type(
175
182
 
176
183
  encoder_name: TypeName | None = None # defining this up here to placate mypy
177
184
  chunks: list[FileContents] = []
185
+
186
+ # Handle $ref - return a forward reference to the registered type
187
+ if isinstance(type, RiverConcreteType) and type.ref is not None:
188
+ ref_id = type.ref
189
+ if ref_id in type_registry:
190
+ # Use forward reference string for the type
191
+ return (TypeName(f'"{type_registry[ref_id].value}"'), [], [], set())
192
+ else:
193
+ # Unknown ref, fall back to Any
194
+ return (TypeName("Any"), [], [], set())
195
+
178
196
  if isinstance(type, RiverNotType):
179
197
  return (NoneTypeExpr(), [], [], set())
180
198
  elif isinstance(type, RiverUnionType):
@@ -269,6 +287,7 @@ def encode_type(
269
287
  base_model,
270
288
  in_module,
271
289
  permit_unknown_members=permit_unknown_members,
290
+ type_registry=type_registry,
272
291
  )
273
292
  one_of.append(type_name)
274
293
  chunks.extend(contents)
@@ -304,6 +323,7 @@ def encode_type(
304
323
  base_model,
305
324
  in_module,
306
325
  permit_unknown_members=permit_unknown_members,
326
+ type_registry=type_registry,
307
327
  )
308
328
  one_of.append(type_name)
309
329
  chunks.extend(contents)
@@ -369,7 +389,8 @@ def encode_type(
369
389
  type = original_type
370
390
  any_of: list[TypeExpression] = []
371
391
 
372
- typeddict_encoder = []
392
+ # Collect (type_check, encoder_expr) pairs for building ternary chain
393
+ encoder_parts: list[tuple[str | None, str]] = []
373
394
  for i, t in enumerate(type.anyOf):
374
395
  type_name, _, contents, _ = encode_type(
375
396
  t,
@@ -377,39 +398,69 @@ def encode_type(
377
398
  base_model,
378
399
  in_module,
379
400
  permit_unknown_members=permit_unknown_members,
401
+ type_registry=type_registry,
380
402
  )
381
403
  any_of.append(type_name)
382
404
  chunks.extend(contents)
383
405
  if isinstance(t, RiverConcreteType):
384
406
  if t.type == "string":
385
- typeddict_encoder.extend(["x", " if isinstance(x, str) else "])
386
- else:
387
- # TODO(dstewart): This structure changed since we were incorrectly
388
- # leaking ListTypeExprs into codegen. This generated
389
- # code is probably wrong.
407
+ encoder_parts.append(("isinstance(x, str)", "x"))
408
+ elif t.type == "array":
390
409
  match type_name:
391
410
  case ListTypeExpr(inner_type_name):
392
- typeddict_encoder.append(
393
- f"encode_{render_literal_type(inner_type_name)}(x)"
411
+ # Primitives don't need encoding
412
+ inner_type_str = render_literal_type(inner_type_name)
413
+ if inner_type_str in ("str", "int", "float", "bool", "Any"):
414
+ encoder_parts.append(("isinstance(x, list)", "list(x)"))
415
+ else:
416
+ encoder_parts.append(
417
+ (
418
+ "isinstance(x, list)",
419
+ f"[encode_{inner_type_str}(y) for y in x]",
420
+ )
421
+ )
422
+ case _:
423
+ encoder_parts.append(("isinstance(x, list)", "list(x)"))
424
+ elif t.type == "object":
425
+ match type_name:
426
+ case TypeName(value):
427
+ encoder_parts.append(
428
+ ("isinstance(x, dict)", f"encode_{value}(x)")
394
429
  )
430
+ case _:
431
+ encoder_parts.append(("isinstance(x, dict)", "dict(x)"))
432
+ elif t.type in ("number", "integer"):
433
+ match type_name:
395
434
  case LiteralTypeExpr(const):
396
- typeddict_encoder.append(repr(const))
435
+ encoder_parts.append((f"x == {repr(const)}", repr(const)))
436
+ case _:
437
+ encoder_parts.append(("isinstance(x, (int, float))", "x"))
438
+ elif t.type == "boolean":
439
+ encoder_parts.append(("isinstance(x, bool)", "x"))
440
+ elif t.type == "null" or t.type == "undefined":
441
+ encoder_parts.append(("x is None", "None"))
442
+ else:
443
+ # Fallback for other types
444
+ match type_name:
397
445
  case TypeName(value):
398
- typeddict_encoder.append(f"encode_{value}(x)")
446
+ encoder_parts.append((None, f"encode_{value}(x)"))
447
+ case LiteralTypeExpr(const):
448
+ encoder_parts.append((None, repr(const)))
399
449
  case NoneTypeExpr():
400
- typeddict_encoder.append("None")
401
- case other:
402
- _o2: (
403
- DictTypeExpr
404
- | OpenUnionTypeExpr
405
- | UnionTypeExpr
406
- | LiteralType
407
- ) = other
408
- raise ValueError(
409
- f"What does it mean to have {
410
- render_type_expr(_o2)
411
- } here?"
412
- )
450
+ encoder_parts.append((None, "None"))
451
+ case _:
452
+ encoder_parts.append((None, "x"))
453
+
454
+ # Build the ternary chain from encoder_parts
455
+ typeddict_encoder = list[str]()
456
+ for i, (type_check, encoder_expr) in enumerate(encoder_parts):
457
+ is_last = i == len(encoder_parts) - 1
458
+ if is_last or type_check is None:
459
+ # Last item or no type check - just the expression
460
+ typeddict_encoder.append(encoder_expr)
461
+ else:
462
+ # Add expression with type check
463
+ typeddict_encoder.append(f"{encoder_expr} if {type_check} else")
413
464
  if permit_unknown_members:
414
465
  union = _make_open_union_type_expr(any_of)
415
466
  else:
@@ -462,6 +513,7 @@ def encode_type(
462
513
  base_model,
463
514
  in_module,
464
515
  permit_unknown_members=permit_unknown_members,
516
+ type_registry=type_registry,
465
517
  )
466
518
  elif isinstance(type, RiverConcreteType):
467
519
  typeddict_encoder = list[str]()
@@ -509,6 +561,7 @@ def encode_type(
509
561
  base_model,
510
562
  in_module,
511
563
  permit_unknown_members=permit_unknown_members,
564
+ type_registry=type_registry,
512
565
  )
513
566
  typeddict_encoder.append("TODO: dstewart")
514
567
  return (ListTypeExpr(type_name), module_info, type_chunks, encoder_names)
@@ -523,10 +576,15 @@ def encode_type(
523
576
  base_model,
524
577
  in_module,
525
578
  permit_unknown_members=permit_unknown_members,
579
+ type_registry=type_registry,
526
580
  )
527
581
  return (DictTypeExpr(type_name), module_info, type_chunks, encoder_names)
528
582
  assert type.type == "object", type.type
529
583
 
584
+ # Register $id for this type so $ref can resolve to it
585
+ if type.id_ is not None:
586
+ type_registry[type.id_] = prefix
587
+
530
588
  current_chunks: list[str] = [
531
589
  f"class {render_literal_type(prefix)}({base_model}):"
532
590
  ]
@@ -551,6 +609,7 @@ def encode_type(
551
609
  "BaseModel" if base_model == "RiverError" else base_model,
552
610
  in_module,
553
611
  permit_unknown_members=permit_unknown_members,
612
+ type_registry=type_registry,
554
613
  )
555
614
  encoder_name = None
556
615
  chunks.extend(contents)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: replit-river
3
- Version: 0.17.12
3
+ Version: 0.17.14
4
4
  Summary: Replit river toolkit for Python
5
5
  Author-email: Replit <eng@replit.com>
6
6
  License: MIT License
@@ -19,7 +19,7 @@ replit_river/transport_options.py,sha256=Kx3n6_x6sA69WV52EUvm-GzJhDaaewUQzbtcdPl
19
19
  replit_river/websocket_wrapper.py,sha256=xrk421A5eXTH2bjAcNeBZN96zTO6xQsl0VS9qcwus6M,814
20
20
  replit_river/codegen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  replit_river/codegen/__main__.py,sha256=LyKe1OXIyev0BuUcu43iu6zBLJzeogQ8DocxDkALD-Q,153
22
- replit_river/codegen/client.py,sha256=EU3cuwDegkLI9V6SG0IWPPdLQvBl6dUyrSuu0JDYGpQ,59963
22
+ replit_river/codegen/client.py,sha256=w8CrFss2-0k0ukCtP6LlPftzSrm7wNgDmuCXTzsr9EQ,62870
23
23
  replit_river/codegen/format.py,sha256=pLa9nWlw8hTOnjzZjMsMpgcmNYiLaF5VAHNQTwwJ7Zw,285
24
24
  replit_river/codegen/run.py,sha256=InJaUDJft80pY7v2l-LoXHr8HYg3Bmb_6XQvlqgvxv4,3170
25
25
  replit_river/codegen/schema.py,sha256=y3kzrEPgzW9gKMjqiF2souZk47mE_kuFkHlsxRdD560,5344
@@ -29,7 +29,7 @@ replit_river/v2/__init__.py,sha256=Fi4wP87qHOQwaWQmVbPJOOiGfkiZ6gTWg5bF5J8je5s,1
29
29
  replit_river/v2/client.py,sha256=PQ1qz15lFTdMOs0kktBdzMUEYD66OnJJN0loYFVjdn4,7241
30
30
  replit_river/v2/client_transport.py,sha256=swtsFoWIX8nnG5cBeHMkZSZsJ5SW-VbdNHBdLtldMgU,3445
31
31
  replit_river/v2/session.py,sha256=8EMKw8bevoIrMfQBKMl3oXFlOJ91lzjmuqsm3qZN8Ts,54147
32
- replit_river-0.17.12.dist-info/METADATA,sha256=K3yvG8yAj4od7kQL3DxmFP3cOUoUWnx7kKHXB2XuZsM,4794
33
- replit_river-0.17.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
34
- replit_river-0.17.12.dist-info/licenses/LICENSE,sha256=kyZ5E3kOH4dzPet_xD0w6xi04e-0fGT0HRMhKyLyLC0,1063
35
- replit_river-0.17.12.dist-info/RECORD,,
32
+ replit_river-0.17.14.dist-info/METADATA,sha256=YWXZDV75qxfsJOebUMG6j4gOwrhFUjYzO_ADA2JMIV8,4794
33
+ replit_river-0.17.14.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
34
+ replit_river-0.17.14.dist-info/licenses/LICENSE,sha256=kyZ5E3kOH4dzPet_xD0w6xi04e-0fGT0HRMhKyLyLC0,1063
35
+ replit_river-0.17.14.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any