sonolus.py 0.12.0__py3-none-any.whl → 0.12.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.

Potentially problematic release.


This version of sonolus.py might be problematic. Click here for more details.

@@ -1308,6 +1308,7 @@ class Visitor(ast.NodeVisitor):
1308
1308
  raise NotImplementedError(f"Unsupported syntax: {type(node).__name__}")
1309
1309
 
1310
1310
  def handle_getattr(self, node: ast.stmt | ast.expr, target: Value, key: str) -> Value:
1311
+ # If this is changed, remember to update the getattr impl too
1311
1312
  with self.reporting_errors_at_node(node):
1312
1313
  if isinstance(target, ConstantValue):
1313
1314
  # Unwrap so we can access fields
@@ -1328,6 +1329,7 @@ class Visitor(ast.NodeVisitor):
1328
1329
  raise TypeError(f"Unsupported field or descriptor {key}")
1329
1330
 
1330
1331
  def handle_setattr(self, node: ast.stmt | ast.expr, target: Value, key: str, value: Value):
1332
+ # If this is changed, remember to update the setattr impl too
1331
1333
  with self.reporting_errors_at_node(node):
1332
1334
  if target._is_py_():
1333
1335
  target = target._as_py_()
@@ -509,7 +509,7 @@ class _BaseArchetype:
509
509
  Args:
510
510
  index: The index of the entity to reference.
511
511
  check: If true, raises an error if the entity at the index is not of this archetype or of a subclass of
512
- this archetype. If false, no validation is performed.
512
+ this archetype. If false, no validation is performed.
513
513
 
514
514
  Returns:
515
515
  The entity at the given index.
@@ -528,7 +528,7 @@ class _BaseArchetype:
528
528
  Args:
529
529
  index: The index of the entity to check.
530
530
  strict: If true, only returns true if the entity is exactly of this archetype. If false, also returns true
531
- if the entity is of a subclass of this archetype.
531
+ if the entity is of a subclass of this archetype.
532
532
 
533
533
  Returns:
534
534
  Whether the entity at the given index is of this archetype.
@@ -1349,7 +1349,7 @@ class EntityRef[A: _BaseArchetype](Record):
1349
1349
 
1350
1350
  Args:
1351
1351
  check: If true, raises an error if the referenced entity is not of this archetype or of a subclass of
1352
- this archetype. If false, no validation is performed.
1352
+ this archetype. If false, no validation is performed.
1353
1353
 
1354
1354
  Returns:
1355
1355
  The entity this reference points to.
@@ -1370,7 +1370,7 @@ class EntityRef[A: _BaseArchetype](Record):
1370
1370
 
1371
1371
  Args:
1372
1372
  strict: If true, only returns true if the entity is exactly of this archetype. If false, also returns true
1373
- if the entity is of a subclass of this archetype.
1373
+ if the entity is of a subclass of this archetype.
1374
1374
 
1375
1375
  Returns:
1376
1376
  Whether the entity at the given index is of this archetype.
@@ -1,4 +1,5 @@
1
- from typing import Never, assert_never
1
+ from types import FunctionType
2
+ from typing import Any, Never, assert_never
2
3
 
3
4
  from sonolus.backend.ops import Op
4
5
  from sonolus.script.array import Array
@@ -389,6 +390,78 @@ def _super(*args):
389
390
  return super(*(arg._as_py_() if arg._is_py_() else arg for arg in args))
390
391
 
391
392
 
393
+ @meta_fn
394
+ def _hasattr(obj: Any, name: str) -> bool:
395
+ from sonolus.script.internal.constant import ConstantValue
396
+ from sonolus.script.internal.descriptor import SonolusDescriptor
397
+
398
+ name = validate_value(name)._as_py_()
399
+ if isinstance(obj, ConstantValue):
400
+ # Unwrap so we can access fields
401
+ obj = obj._as_py_()
402
+ descriptor = None
403
+ for cls in type.mro(type(obj)):
404
+ descriptor = cls.__dict__.get(name, None)
405
+ if descriptor is not None:
406
+ break
407
+ # We want to mirror what getattr supports and fail fast if a future getattr would fail.
408
+ match descriptor:
409
+ case None:
410
+ return hasattr(obj, name)
411
+ case property() | SonolusDescriptor() | FunctionType() | classmethod() | staticmethod():
412
+ return True
413
+ case non_descriptor if not hasattr(non_descriptor, "__get__"):
414
+ return True
415
+ case _:
416
+ raise TypeError(f"Unsupported field or descriptor {name}")
417
+
418
+
419
+ @meta_fn
420
+ def _getattr(obj: Any, name: str, default=_empty) -> Any:
421
+ from sonolus.backend.visitor import compile_and_call
422
+ from sonolus.script.internal.constant import ConstantValue
423
+ from sonolus.script.internal.descriptor import SonolusDescriptor
424
+
425
+ name = validate_value(name)._as_py_()
426
+ if isinstance(obj, ConstantValue):
427
+ # Unwrap so we can access fields
428
+ obj = obj._as_py_()
429
+ descriptor = None
430
+ for cls in type.mro(type(obj)):
431
+ descriptor = cls.__dict__.get(name, None)
432
+ if descriptor is not None:
433
+ break
434
+ match descriptor:
435
+ case property(fget=getter):
436
+ return compile_and_call(getter, obj)
437
+ case SonolusDescriptor() | FunctionType() | classmethod() | staticmethod() | None:
438
+ return validate_value(getattr(obj, name) if default is _empty else getattr(obj, name, default))
439
+ case non_descriptor if not hasattr(non_descriptor, "__get__"):
440
+ return validate_value(getattr(obj, name) if default is _empty else getattr(obj, name, default))
441
+ case _:
442
+ raise TypeError(f"Unsupported field or descriptor {name}")
443
+
444
+
445
+ @meta_fn
446
+ def _setattr(obj: Any, name: str, value: Any):
447
+ from sonolus.backend.visitor import compile_and_call
448
+ from sonolus.script.internal.descriptor import SonolusDescriptor
449
+
450
+ name = validate_value(name)._as_py_()
451
+ if obj._is_py_():
452
+ obj = obj._as_py_()
453
+ descriptor = getattr(type(obj), name, None)
454
+ match descriptor:
455
+ case property(fset=setter):
456
+ if setter is None:
457
+ raise AttributeError(f"Cannot set attribute {name} because property has no setter")
458
+ compile_and_call(setter, obj, value)
459
+ case SonolusDescriptor():
460
+ setattr(obj, name, value)
461
+ case _:
462
+ raise TypeError(f"Unsupported field or descriptor {name}")
463
+
464
+
392
465
  class _Type(Record):
393
466
  @meta_fn
394
467
  def __call__(self, value, /):
@@ -412,12 +485,13 @@ BUILTIN_IMPLS = {
412
485
  id(abs): _abs,
413
486
  id(all): _all,
414
487
  id(any): _any,
415
- id(sum): _sum,
416
488
  id(bool): _bool,
417
489
  id(callable): _callable,
418
490
  id(enumerate): _enumerate,
419
491
  id(filter): _filter,
420
492
  id(float): _float,
493
+ id(getattr): _getattr,
494
+ id(hasattr): _hasattr,
421
495
  id(int): _int,
422
496
  id(isinstance): _isinstance,
423
497
  id(iter): _iter,
@@ -428,6 +502,8 @@ BUILTIN_IMPLS = {
428
502
  id(next): _next,
429
503
  id(range): Range,
430
504
  id(reversed): _reversed,
505
+ id(setattr): _setattr,
506
+ id(sum): _sum,
431
507
  id(super): _super,
432
508
  id(type): _type,
433
509
  id(zip): _zip,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sonolus.py
3
- Version: 0.12.0
3
+ Version: 0.12.1
4
4
  Summary: Sonolus engine development in Python
5
5
  Project-URL: Documentation, https://sonolus.py.qwewqa.xyz/
6
6
  Project-URL: Repository, https://github.com/qwewqa/sonolus.py
@@ -11,7 +11,7 @@ sonolus/backend/node.py,sha256=w5y2GwSc2E9rQvGJNaMzvPW_FYjjfHw4QDUmKs1dAnc,714
11
11
  sonolus/backend/ops.py,sha256=5weB_vIxbkwCSJuzYZyKUk7vVXsSIEDJYRlvE-2ke8A,10572
12
12
  sonolus/backend/place.py,sha256=7qwV732hZ4WP-9GNN8FQSEKssPJZELip1wLXTWfop7Y,4717
13
13
  sonolus/backend/utils.py,sha256=OwD1EPh8j-hsfkLzeKNzPQojT_3kklpJou0WTJNoCbc,2337
14
- sonolus/backend/visitor.py,sha256=lEq_lkCh74_mK_saE4JeRI9_mM8MMeWRzw4mqJ0Et7c,64450
14
+ sonolus/backend/visitor.py,sha256=0EO5EgACDHpbITvKMbdP4EmoIbBDmZtZjnup9jksf_E,64590
15
15
  sonolus/backend/optimize/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  sonolus/backend/optimize/allocate.py,sha256=CuumoMphkpQlGRNeKLHT4FBGE0XVj5pwhfNdrqiLFSs,7535
17
17
  sonolus/backend/optimize/constant_evaluation.py,sha256=_u_VfLmd4Rlq9aKyRSeKb47352CXuf8uNgNhNTK1qe0,21510
@@ -35,7 +35,7 @@ sonolus/build/level.py,sha256=KLqUAtxIuIqrzeFURJA97rdqjA5pcvYSmwNZQhElaMQ,702
35
35
  sonolus/build/node.py,sha256=Dhuz_-UlRd-EJC7-AP1NuyvrjHWNo7jGssniRh4dZhI,1239
36
36
  sonolus/build/project.py,sha256=Uuz82QtTNFdklrVJ_i7EPp8hSjyOxLU1xAeOloa6G00,8579
37
37
  sonolus/script/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
- sonolus/script/archetype.py,sha256=qK1tcREt56qJPh1zw_cjZGz0UUQngLGXUDA1HmwNpY8,55083
38
+ sonolus/script/archetype.py,sha256=bDTjhbNA-F0wXOiYh1_cRewIT2S2D9zcL2XerBhobPI,55113
39
39
  sonolus/script/array.py,sha256=EbrNwl_WuJ0JjjkX0s_VJNXWqvYdm_ljTbyrDEMLGUY,13348
40
40
  sonolus/script/array_like.py,sha256=E6S4TW2muXgcyVkhUASQVt7JSYUkpvdJPgHz6YiSHNo,14708
41
41
  sonolus/script/bucket.py,sha256=LNePLmCwgXfKLmH4Z7ZcTFKWR32eq4AnnagI7jacrsU,7782
@@ -69,7 +69,7 @@ sonolus/script/ui.py,sha256=DYPGWIjHj1IFPxW1zaEuIUQx0b32FJPXtiwCvrtJ6oo,7528
69
69
  sonolus/script/values.py,sha256=6iJG6h4IDlbcK8FH4GENSHOQc7C_7fCGa34wM80qToA,1629
70
70
  sonolus/script/vec.py,sha256=f7keqogIQiRpuQ0dULOFCxFlmvkykoFZMFwYw9P39Kk,9319
71
71
  sonolus/script/internal/__init__.py,sha256=T6rzLoiOUaiSQtaHMZ88SNO-ijSjSSv33TKtUwu-Ms8,136
72
- sonolus/script/internal/builtin_impls.py,sha256=1fo6UuWlaLoqpVwFSrFS5BabNeRCdS2T2mjsS4BPYcY,13603
72
+ sonolus/script/internal/builtin_impls.py,sha256=6MST5yII1Y6Ozo3P6WKOfWLTPllPOsxVNPSNmWAl7jU,16556
73
73
  sonolus/script/internal/callbacks.py,sha256=vWzJG8uiJoEtsNnbeZPqOHogCwoLpz2D1MnHY2wVV8s,2801
74
74
  sonolus/script/internal/constant.py,sha256=3ycbGkDJVUwcrCZ96vLjAoAARgsvaqDM8rJ_YCrLrvo,4289
75
75
  sonolus/script/internal/context.py,sha256=dhWQS7fFPMhb0FJyw3y--0HlBtwuYANdIYiv7u_96jk,22023
@@ -87,8 +87,8 @@ sonolus/script/internal/simulation_context.py,sha256=LGxLTvxbqBIhoe1R-SfwGajNIDw
87
87
  sonolus/script/internal/transient.py,sha256=y2AWABqF1aoaP6H4_2u4MMpNioC4OsZQCtPyNI0txqo,1634
88
88
  sonolus/script/internal/tuple_impl.py,sha256=WaI5HSF5h03ddXiSHEwzY9ttfsPUItaf86Y5VbZypek,3754
89
89
  sonolus/script/internal/value.py,sha256=OngrCdmY_h6mV2Zgwqhuo4eYFad0kTk6263UAxctZcY,6963
90
- sonolus_py-0.12.0.dist-info/METADATA,sha256=ncmBBjgZ1BHrxEb9xrtEIa_CiF8pK-lknGve69U3_LY,556
91
- sonolus_py-0.12.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
92
- sonolus_py-0.12.0.dist-info/entry_points.txt,sha256=oTYspY_b7SA8TptEMTDxh4-Aj-ZVPnYC9f1lqH6s9G4,54
93
- sonolus_py-0.12.0.dist-info/licenses/LICENSE,sha256=JEKpqVhQYfEc7zg3Mj462sKbKYmO1K7WmvX1qvg9IJk,1067
94
- sonolus_py-0.12.0.dist-info/RECORD,,
90
+ sonolus_py-0.12.1.dist-info/METADATA,sha256=fh6sYiAQtG6zvJO4a66E2bQz_KOVNxzrAxhMMVl36_A,556
91
+ sonolus_py-0.12.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
92
+ sonolus_py-0.12.1.dist-info/entry_points.txt,sha256=oTYspY_b7SA8TptEMTDxh4-Aj-ZVPnYC9f1lqH6s9G4,54
93
+ sonolus_py-0.12.1.dist-info/licenses/LICENSE,sha256=JEKpqVhQYfEc7zg3Mj462sKbKYmO1K7WmvX1qvg9IJk,1067
94
+ sonolus_py-0.12.1.dist-info/RECORD,,