astreum 0.2.5__tar.gz → 0.2.7__tar.gz

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 astreum might be problematic. Click here for more details.

Files changed (24) hide show
  1. {astreum-0.2.5/src/astreum.egg-info → astreum-0.2.7}/PKG-INFO +1 -1
  2. {astreum-0.2.5 → astreum-0.2.7}/pyproject.toml +1 -1
  3. {astreum-0.2.5 → astreum-0.2.7}/src/astreum/node.py +116 -125
  4. {astreum-0.2.5 → astreum-0.2.7/src/astreum.egg-info}/PKG-INFO +1 -1
  5. {astreum-0.2.5 → astreum-0.2.7}/LICENSE +0 -0
  6. {astreum-0.2.5 → astreum-0.2.7}/README.md +0 -0
  7. {astreum-0.2.5 → astreum-0.2.7}/setup.cfg +0 -0
  8. {astreum-0.2.5 → astreum-0.2.7}/src/astreum/__init__.py +0 -0
  9. {astreum-0.2.5 → astreum-0.2.7}/src/astreum/_node/__init__.py +0 -0
  10. {astreum-0.2.5 → astreum-0.2.7}/src/astreum/_node/storage/__init__.py +0 -0
  11. {astreum-0.2.5 → astreum-0.2.7}/src/astreum/_node/storage/merkle.py +0 -0
  12. {astreum-0.2.5 → astreum-0.2.7}/src/astreum/_node/storage/patricia.py +0 -0
  13. {astreum-0.2.5 → astreum-0.2.7}/src/astreum/crypto/__init__.py +0 -0
  14. {astreum-0.2.5 → astreum-0.2.7}/src/astreum/crypto/ed25519.py +0 -0
  15. {astreum-0.2.5 → astreum-0.2.7}/src/astreum/crypto/x25519.py +0 -0
  16. {astreum-0.2.5 → astreum-0.2.7}/src/astreum/format.py +0 -0
  17. {astreum-0.2.5 → astreum-0.2.7}/src/astreum/lispeum/__init__.py +0 -0
  18. {astreum-0.2.5 → astreum-0.2.7}/src/astreum/lispeum/parser.py +0 -0
  19. {astreum-0.2.5 → astreum-0.2.7}/src/astreum/lispeum/tokenizer.py +0 -0
  20. {astreum-0.2.5 → astreum-0.2.7}/src/astreum.egg-info/SOURCES.txt +0 -0
  21. {astreum-0.2.5 → astreum-0.2.7}/src/astreum.egg-info/dependency_links.txt +0 -0
  22. {astreum-0.2.5 → astreum-0.2.7}/src/astreum.egg-info/requires.txt +0 -0
  23. {astreum-0.2.5 → astreum-0.2.7}/src/astreum.egg-info/top_level.txt +0 -0
  24. {astreum-0.2.5 → astreum-0.2.7}/tests/test_node_machine.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: astreum
3
- Version: 0.2.5
3
+ Version: 0.2.7
4
4
  Summary: Python library to interact with the Astreum blockchain and its Lispeum virtual machine.
5
5
  Author-email: "Roy R. O. Okello" <roy@stelar.xyz>
6
6
  Project-URL: Homepage, https://github.com/astreum/lib
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "astreum"
3
- version = "0.2.5"
3
+ version = "0.2.7"
4
4
  authors = [
5
5
  { name="Roy R. O. Okello", email="roy@stelar.xyz" },
6
6
  ]
@@ -289,27 +289,43 @@ class Expr:
289
289
  return f'(error "{self.message}" in {self.origin})'
290
290
 
291
291
  class Env:
292
- def __init__(self, parent_id: uuid.UUID = None):
293
- self.data: Dict[str, Expr] = {}
294
- self.parent_id = parent_id
295
-
296
- def put(self, name: str, value: Expr):
292
+ def __init__(
293
+ self,
294
+ data: Optional[Dict[str, Expr]] = None,
295
+ parent_id: Optional[uuid.UUID] = None,
296
+ max_exprs: Optional[int] = 8,
297
+ ):
298
+ self.data: Dict[str, Expr] = data if data is not None else {}
299
+ self.parent_id: Optional[uuid.UUID] = parent_id
300
+ self.max_exprs: Optional[int] = max_exprs
301
+
302
+ def put(self, name: str, value: Expr) -> None:
303
+ if (
304
+ self.max_exprs is not None
305
+ and name not in self.data
306
+ and len(self.data) >= self.max_exprs
307
+ ):
308
+ raise RuntimeError(
309
+ f"environment full: {len(self.data)} ≥ max_exprs={self.max_exprs}"
310
+ )
297
311
  self.data[name] = value
298
312
 
299
313
  def get(self, name: str) -> Optional[Expr]:
300
- if name in self.data:
301
- return self.data[name]
302
- elif self.parent is not None:
303
- return self.parent.get(name)
304
- else:
305
- return None
314
+ return self.data.get(name)
315
+
316
+ def pop(self, name: str) -> Optional[Expr]:
317
+ return self.data.pop(name, None)
306
318
 
307
- def __repr__(self):
308
- return f"Env({self.data})"
319
+ def __repr__(self) -> str:
320
+ return (
321
+ f"Env(size={len(self.data)}, "
322
+ f"max_exprs={self.max_exprs}, "
323
+ f"parent_id={self.parent_id})"
324
+ )
309
325
 
310
326
 
311
327
  class Node:
312
- def __init__(self, config: dict):
328
+ def __init__(self, config: dict = {}):
313
329
  self._machine_setup()
314
330
  machine_only = bool(config.get('machine-only', True))
315
331
  if not machine_only:
@@ -706,14 +722,19 @@ class Node:
706
722
  self.environments[env_id] = Env(parent_id=parent_id)
707
723
  return env_id
708
724
 
709
- def machine_get_or_create_environment(self, env_id: Optional[uuid.UUID] = None, parent_id: Optional[uuid.UUID] = None) -> uuid.UUID:
725
+ def machine_get_or_create_environment(
726
+ self,
727
+ env_id: Optional[uuid.UUID] = None,
728
+ parent_id: Optional[uuid.UUID] = None,
729
+ max_exprs: Optional[int] = None
730
+ ) -> uuid.UUID:
710
731
  with self.machine_environments_lock:
711
732
  if env_id is not None and env_id in self.environments:
712
733
  return env_id
713
734
  new_id = env_id if env_id is not None else uuid.uuid4()
714
735
  while new_id in self.environments:
715
736
  new_id = uuid.uuid4()
716
- self.environments[new_id] = Env(parent_id=parent_id)
737
+ self.environments[new_id] = Env(parent_id=parent_id, max_exprs=max_exprs)
717
738
  return new_id
718
739
 
719
740
  def machine_delete_environment(self, env_id: uuid.UUID) -> bool:
@@ -911,120 +932,90 @@ class Node:
911
932
  # env=env,
912
933
  # )
913
934
 
914
- # Integer
935
+ # Integer arithmetic primitives
915
936
  elif first.value == "+":
916
937
  args = expr.elements[1:]
917
- if len(args) == 0:
918
- return Expr.Error(message="'+' expects at least 1 argument", origin=expr)
919
- evaluated_args = []
920
- for arg in args:
921
- val = self.machine_expr_eval(env_id==env_id, expr=arg)
922
- if isinstance(val, Expr.Error):
923
- return val
924
- evaluated_args.append(val)
925
- if not all(isinstance(val, Expr.Integer) for val in evaluated_args):
926
- offending = next(val for val in evaluated_args if not isinstance(val, Expr.Integer))
927
- return Expr.Error(message="'+' only accepts integer operands", origin=offending)
928
- result = sum(val.value for val in evaluated_args)
938
+ if not args:
939
+ return Expr.Error("'+' expects at least 1 argument", origin=expr)
940
+ vals = [self.machine_expr_eval(env_id=env_id, expr=a) for a in args]
941
+ for v in vals:
942
+ if isinstance(v, Expr.Error): return v
943
+ if not isinstance(v, Expr.Integer):
944
+ return Expr.Error("'+' only accepts integer operands", origin=v)
945
+ return Expr.Integer(abs(vals[0].value) if len(vals) == 1
946
+ else sum(v.value for v in vals))
947
+
948
+ elif first.value == "-":
949
+ args = expr.elements[1:]
950
+ if not args:
951
+ return Expr.Error("'-' expects at least 1 argument", origin=expr)
952
+ vals = [self.machine_expr_eval(env_id=env_id, expr=a) for a in args]
953
+ for v in vals:
954
+ if isinstance(v, Expr.Error): return v
955
+ if not isinstance(v, Expr.Integer):
956
+ return Expr.Error("'-' only accepts integer operands", origin=v)
957
+ if len(vals) == 1:
958
+ return Expr.Integer(-vals[0].value)
959
+ result = vals[0].value
960
+ for v in vals[1:]:
961
+ result -= v.value
929
962
  return Expr.Integer(result)
930
-
931
- # # Subtraction
932
- # elif first.value == "-":
933
- # evaluated_args = [self.evaluate_expression(arg, env) for arg in expr.elements[1:]]
934
-
935
- # # Check for non-integer arguments
936
- # if not all(isinstance(arg, Expr.Integer) for arg in evaluated_args):
937
- # return Expr.Error(
938
- # category="TypeError",
939
- # message="All arguments to - must be integers"
940
- # )
941
-
942
- # # With only one argument, negate it
943
- # if len(evaluated_args) == 1:
944
- # return Expr.Integer(-evaluated_args[0].value)
945
-
946
- # # With multiple arguments, subtract all from the first
947
- # result = evaluated_args[0].value
948
- # for arg in evaluated_args[1:]:
949
- # result -= arg.value
950
-
951
- # return Expr.Integer(result)
952
-
953
- # # Multiplication
954
- # elif first.value == "*":
955
- # evaluated_args = [self.evaluate_expression(arg, env) for arg in expr.elements[1:]]
956
963
 
957
- # # Check for non-integer arguments
958
- # if not all(isinstance(arg, Expr.Integer) for arg in evaluated_args):
959
- # return Expr.Error(
960
- # category="TypeError",
961
- # message="All arguments to * must be integers"
962
- # )
963
-
964
- # # Multiply all values
965
- # result = 1
966
- # for arg in evaluated_args:
967
- # result *= arg.value
968
-
969
- # return Expr.Integer(result)
970
-
971
- # # Division (integer division)
972
- # elif first.value == "/":
973
- # evaluated_args = [self.evaluate_expression(arg, env) for arg in expr.elements[1:]]
974
-
975
- # # Check for non-integer arguments
976
- # if not all(isinstance(arg, Expr.Integer) for arg in evaluated_args):
977
- # return Expr.Error(
978
- # category="TypeError",
979
- # message="All arguments to / must be integers"
980
- # )
981
-
982
- # # Need exactly two arguments
983
- # if len(evaluated_args) != 2:
984
- # return Expr.Error(
985
- # category="ArgumentError",
986
- # message="The / operation requires exactly two arguments"
987
- # )
988
-
989
- # dividend = evaluated_args[0].value
990
- # divisor = evaluated_args[1].value
991
-
992
- # if divisor == 0:
993
- # return Expr.Error(
994
- # category="DivisionError",
995
- # message="Division by zero"
996
- # )
997
-
998
- # return Expr.Integer(dividend // divisor) # Integer division
999
-
1000
- # # Remainder (modulo)
1001
- # elif first.value == "%":
1002
- # evaluated_args = [self.evaluate_expression(arg, env) for arg in expr.elements[1:]]
964
+ elif first.value == "/":
965
+ args = expr.elements[1:]
966
+ if len(args) < 2:
967
+ return Expr.Error("'/' expects at least 2 arguments", origin=expr)
968
+ vals = [self.machine_expr_eval(env_id=env_id, expr=a) for a in args]
969
+ for v in vals:
970
+ if isinstance(v, Expr.Error): return v
971
+ if not isinstance(v, Expr.Integer):
972
+ return Expr.Error("'/' only accepts integer operands", origin=v)
973
+ result = vals[0].value
974
+ for v in vals[1:]:
975
+ if v.value == 0:
976
+ return Expr.Error("division by zero", origin=v)
977
+ if result % v.value:
978
+ return Expr.Error("non-exact division", origin=expr)
979
+ result //= v.value
980
+ return Expr.Integer(result)
1003
981
 
1004
- # # Check for non-integer arguments
1005
- # if not all(isinstance(arg, Expr.Integer) for arg in evaluated_args):
1006
- # return Expr.Error(
1007
- # category="TypeError",
1008
- # message="All arguments to % must be integers"
1009
- # )
1010
-
1011
- # # Need exactly two arguments
1012
- # if len(evaluated_args) != 2:
1013
- # return Expr.Error(
1014
- # category="ArgumentError",
1015
- # message="The % operation requires exactly two arguments"
1016
- # )
1017
-
1018
- # dividend = evaluated_args[0].value
1019
- # divisor = evaluated_args[1].value
1020
-
1021
- # if divisor == 0:
1022
- # return Expr.Error(
1023
- # category="DivisionError",
1024
- # message="Modulo by zero"
1025
- # )
1026
-
1027
- # return Expr.Integer(dividend % divisor)
982
+ elif first.value == "%":
983
+ if len(expr.elements) != 3:
984
+ return Expr.Error("'%' expects exactly 2 arguments", origin=expr)
985
+ a = self.machine_expr_eval(env_id=env_id, expr=expr.elements[1])
986
+ b = self.machine_expr_eval(env_id=env_id, expr=expr.elements[2])
987
+ for v in (a, b):
988
+ if isinstance(v, Expr.Error): return v
989
+ if not isinstance(v, Expr.Integer):
990
+ return Expr.Error("'%' only accepts integer operands", origin=v)
991
+ if b.value == 0:
992
+ return Expr.Error("division by zero", origin=expr.elements[2])
993
+ return Expr.Integer(a.value % b.value)
994
+
995
+ elif first.value in ("=", "!=", ">", "<", ">=", "<="):
996
+ args = expr.elements[1:]
997
+ if len(args) != 2:
998
+ return Expr.Error(f"'{first.value}' expects exactly 2 arguments", origin=expr)
999
+
1000
+ left = self.machine_expr_eval(env_id=env_id, expr=args[0])
1001
+ right = self.machine_expr_eval(env_id=env_id, expr=args[1])
1002
+
1003
+ for v in (left, right):
1004
+ if isinstance(v, Expr.Error):
1005
+ return v
1006
+ if not isinstance(v, Expr.Integer):
1007
+ return Expr.Error(f"'{first.value}' only accepts integer operands", origin=v)
1008
+
1009
+ a, b = left.value, right.value
1010
+ match first.value:
1011
+ case "=": res = a == b
1012
+ case "!=": res = a != b
1013
+ case ">": res = a > b
1014
+ case "<": res = a < b
1015
+ case ">=": res = a >= b
1016
+ case "<=": res = a <= b
1017
+
1018
+ return Expr.Boolean(res)
1028
1019
 
1029
1020
  else:
1030
1021
  evaluated_elements = [self.machine_expr_eval(env_id=env_id, expr=e) for e in expr.elements]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: astreum
3
- Version: 0.2.5
3
+ Version: 0.2.7
4
4
  Summary: Python library to interact with the Astreum blockchain and its Lispeum virtual machine.
5
5
  Author-email: "Roy R. O. Okello" <roy@stelar.xyz>
6
6
  Project-URL: Homepage, https://github.com/astreum/lib
File without changes
File without changes
File without changes
File without changes
File without changes