jmux 0.0.2__tar.gz → 0.0.3__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.
Files changed (29) hide show
  1. {jmux-0.0.2/src/jmux.egg-info → jmux-0.0.3}/PKG-INFO +1 -1
  2. {jmux-0.0.2 → jmux-0.0.3}/src/jmux/demux.py +32 -22
  3. {jmux-0.0.2 → jmux-0.0.3}/src/jmux/helpers.py +12 -2
  4. {jmux-0.0.2 → jmux-0.0.3}/src/jmux/types.py +2 -1
  5. {jmux-0.0.2 → jmux-0.0.3/src/jmux.egg-info}/PKG-INFO +1 -1
  6. jmux-0.0.3/tests/test_demux__parse.py +447 -0
  7. jmux-0.0.2/tests/test_demux__parse.py +0 -386
  8. {jmux-0.0.2 → jmux-0.0.3}/.github/workflows/ci.yml +0 -0
  9. {jmux-0.0.2 → jmux-0.0.3}/.gitignore +0 -0
  10. {jmux-0.0.2 → jmux-0.0.3}/LICENSE +0 -0
  11. {jmux-0.0.2 → jmux-0.0.3}/README.md +0 -0
  12. {jmux-0.0.2 → jmux-0.0.3}/pyproject.toml +0 -0
  13. {jmux-0.0.2 → jmux-0.0.3}/setup.cfg +0 -0
  14. {jmux-0.0.2 → jmux-0.0.3}/src/jmux/__init__.py +0 -0
  15. {jmux-0.0.2 → jmux-0.0.3}/src/jmux/awaitable.py +0 -0
  16. {jmux-0.0.2 → jmux-0.0.3}/src/jmux/decoder.py +0 -0
  17. {jmux-0.0.2 → jmux-0.0.3}/src/jmux/error.py +0 -0
  18. {jmux-0.0.2 → jmux-0.0.3}/src/jmux/pda.py +0 -0
  19. {jmux-0.0.2 → jmux-0.0.3}/src/jmux.egg-info/SOURCES.txt +0 -0
  20. {jmux-0.0.2 → jmux-0.0.3}/src/jmux.egg-info/dependency_links.txt +0 -0
  21. {jmux-0.0.2 → jmux-0.0.3}/src/jmux.egg-info/requires.txt +0 -0
  22. {jmux-0.0.2 → jmux-0.0.3}/src/jmux.egg-info/top_level.txt +0 -0
  23. {jmux-0.0.2 → jmux-0.0.3}/tests/conftest.py +0 -0
  24. {jmux-0.0.2 → jmux-0.0.3}/tests/test_awaitables.py +0 -0
  25. {jmux-0.0.2 → jmux-0.0.3}/tests/test_decoder.py +0 -0
  26. {jmux-0.0.2 → jmux-0.0.3}/tests/test_demux__stream.py +0 -0
  27. {jmux-0.0.2 → jmux-0.0.3}/tests/test_demux__validate.py +0 -0
  28. {jmux-0.0.2 → jmux-0.0.3}/tests/test_helpers.py +0 -0
  29. {jmux-0.0.2 → jmux-0.0.3}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jmux
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: JMux: A Python package for demultiplexing a JSON string into multiple awaitable variables.
5
5
  Author-email: "Johannes A.I. Unruh" <johannes@unruh.ai>
6
6
  License: MIT License
@@ -32,7 +32,7 @@ from jmux.error import (
32
32
  from jmux.helpers import (
33
33
  extract_types_from_generic_alias,
34
34
  get_main_type,
35
- is_json_whitespace,
35
+ str_to_bool,
36
36
  )
37
37
  from jmux.pda import PushDownAutomata
38
38
  from jmux.types import (
@@ -47,12 +47,13 @@ from jmux.types import (
47
47
  JSON_FALSE,
48
48
  JSON_NULL,
49
49
  JSON_TRUE,
50
+ JSON_WHITESPACE,
50
51
  NULL_ALLOWED,
51
52
  NULL_OPEN,
52
53
  NUMBER_OPEN,
53
54
  OBJECT_CLOSE,
54
55
  OBJECT_OPEN,
55
- PRIMITIVE_STATES,
56
+ PARSING_PRIMITIVE_STATES,
56
57
  QUOTE,
57
58
  )
58
59
  from jmux.types import Mode as M
@@ -421,7 +422,7 @@ class JMux(ABC):
421
422
  case None:
422
423
  match self._pda.state:
423
424
  case S.START:
424
- if is_json_whitespace(ch):
425
+ if ch in JSON_WHITESPACE:
425
426
  pass
426
427
  elif ch in OBJECT_OPEN:
427
428
  self._pda.push(M.ROOT)
@@ -434,7 +435,7 @@ class JMux(ABC):
434
435
  "JSON must start with '{' character.",
435
436
  )
436
437
  case S.END:
437
- if is_json_whitespace(ch):
438
+ if ch in JSON_WHITESPACE:
438
439
  pass
439
440
  else:
440
441
  raise ObjectAlreadyClosedError(
@@ -458,7 +459,7 @@ class JMux(ABC):
458
459
  case M.ROOT:
459
460
  match self._pda.state:
460
461
  case S.EXPECT_KEY:
461
- if is_json_whitespace(ch):
462
+ if ch in JSON_WHITESPACE:
462
463
  pass
463
464
  elif ch == '"':
464
465
  self._pda.set_state(S.PARSING_KEY)
@@ -485,7 +486,7 @@ class JMux(ABC):
485
486
  self._decoder.push(ch)
486
487
 
487
488
  case S.EXPECT_COLON:
488
- if is_json_whitespace(ch):
489
+ if ch in JSON_WHITESPACE:
489
490
  pass
490
491
  elif ch in COLON:
491
492
  self._pda.set_state(S.EXPECT_VALUE)
@@ -498,7 +499,7 @@ class JMux(ABC):
498
499
  )
499
500
 
500
501
  case S.EXPECT_VALUE:
501
- if is_json_whitespace(ch):
502
+ if ch in JSON_WHITESPACE:
502
503
  pass
503
504
  elif res := await self._handle_common__expect_value(ch):
504
505
  if (
@@ -550,20 +551,20 @@ class JMux(ABC):
550
551
  ):
551
552
  await self._sink.emit(maybe_char)
552
553
 
553
- case _ if self._pda.state in PRIMITIVE_STATES:
554
- if ch not in COMMA | OBJECT_CLOSE:
555
- self._assert_primitive_character_allowed_in_state(ch)
556
- self._decoder.push(ch)
557
- else:
554
+ case _ if self._pda.state in PARSING_PRIMITIVE_STATES:
555
+ if ch in COMMA | OBJECT_CLOSE | JSON_WHITESPACE:
558
556
  await self._parse_primitive()
559
557
  await self._sink.close()
560
558
  self._decoder.reset()
561
559
  self._pda.set_state(S.EXPECT_KEY)
562
560
  if ch in OBJECT_CLOSE:
563
561
  await self._finalize()
562
+ else:
563
+ self._assert_primitive_character_allowed_in_state(ch)
564
+ self._decoder.push(ch)
564
565
 
565
566
  case S.EXPECT_COMMA_OR_EOC:
566
- if is_json_whitespace(ch):
567
+ if ch in JSON_WHITESPACE:
567
568
  pass
568
569
  elif ch in COMMA:
569
570
  self._pda.set_state(S.EXPECT_KEY)
@@ -596,7 +597,7 @@ class JMux(ABC):
596
597
 
597
598
  match self._pda.state:
598
599
  case S.EXPECT_VALUE:
599
- if is_json_whitespace(ch):
600
+ if ch in JSON_WHITESPACE:
600
601
  pass
601
602
  elif await self._handle_common__expect_value(ch):
602
603
  pass
@@ -638,20 +639,20 @@ class JMux(ABC):
638
639
  else:
639
640
  self._decoder.push(ch)
640
641
 
641
- case _ if self._pda.state in PRIMITIVE_STATES:
642
- if ch not in COMMA | ARRAY_CLOSE:
643
- self._assert_primitive_character_allowed_in_state(ch)
644
- self._decoder.push(ch)
645
- else:
642
+ case _ if self._pda.state in PARSING_PRIMITIVE_STATES:
643
+ if ch in COMMA | ARRAY_CLOSE | JSON_WHITESPACE:
646
644
  await self._parse_primitive()
647
645
  self._decoder.reset()
648
646
  if ch in COMMA:
649
647
  self._pda.set_state(S.EXPECT_VALUE)
650
648
  elif ch in ARRAY_CLOSE:
651
649
  await self._close_context(S.EXPECT_COMMA_OR_EOC)
650
+ else:
651
+ self._assert_primitive_character_allowed_in_state(ch)
652
+ self._decoder.push(ch)
652
653
 
653
654
  case S.EXPECT_COMMA_OR_EOC:
654
- if is_json_whitespace(ch):
655
+ if ch in JSON_WHITESPACE:
655
656
  pass
656
657
  elif ch in COMMA:
657
658
  self._pda.set_state(S.EXPECT_VALUE)
@@ -681,8 +682,16 @@ class JMux(ABC):
681
682
  self._pda.state,
682
683
  "State in object context must be 'parsing_object'",
683
684
  )
684
- if ch in OBJECT_CLOSE:
685
+ if ch in OBJECT_OPEN:
686
+ if self._pda.top is M.OBJECT:
687
+ await self._sink.forward_char(ch)
688
+ self._pda.push(M.OBJECT)
689
+ elif ch in OBJECT_CLOSE:
685
690
  self._pda.pop()
691
+ if self._pda.top is M.OBJECT:
692
+ await self._sink.forward_char(ch)
693
+ return
694
+
686
695
  if self._pda.top is M.ROOT:
687
696
  await self._sink.close()
688
697
  self._pda.set_state(S.EXPECT_COMMA_OR_EOC)
@@ -699,7 +708,8 @@ class JMux(ABC):
699
708
  )
700
709
  await self._sink.emit(None)
701
710
  elif self._pda.state is S.PARSING_BOOLEAN:
702
- await self._sink.emit(self._decoder.buffer == JSON_TRUE)
711
+ bool_value = str_to_bool(self._decoder.buffer)
712
+ await self._sink.emit(bool_value)
703
713
  else:
704
714
  try:
705
715
  buffer = self._decoder.buffer
@@ -1,9 +1,19 @@
1
1
  from types import NoneType, UnionType
2
2
  from typing import Set, Tuple, Type, Union, get_args, get_origin
3
3
 
4
+ from jmux.error import ParsePrimitiveError
4
5
 
5
- def is_json_whitespace(ch: str) -> bool:
6
- return ch in {" ", "\t", "\n", "\r"}
6
+
7
+ def str_to_bool(s: str) -> bool:
8
+ if s == "true":
9
+ return True
10
+ elif s == "false":
11
+ return False
12
+ else:
13
+ raise ParsePrimitiveError(
14
+ f"Cannot convert string '{s}' to boolean. Expected 'true' or 'false', got"
15
+ f" '{s}'."
16
+ )
7
17
 
8
18
 
9
19
  def extract_types_from_generic_alias(UnknownType: Type) -> Tuple[Set[Type], Set[Type]]:
@@ -21,7 +21,7 @@ class State(Enum):
21
21
  PARSING_OBJECT = "parsing_object"
22
22
 
23
23
 
24
- PRIMITIVE_STATES: Set[State] = {
24
+ PARSING_PRIMITIVE_STATES: Set[State] = {
25
25
  State.PARSING_INTEGER,
26
26
  State.PARSING_FLOAT,
27
27
  State.PARSING_BOOLEAN,
@@ -55,3 +55,4 @@ NULL_ALLOWED = set("nul")
55
55
  JSON_FALSE = "false"
56
56
  JSON_TRUE = "true"
57
57
  JSON_NULL = "null"
58
+ JSON_WHITESPACE = set(" \t\n\r")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jmux
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: JMux: A Python package for demultiplexing a JSON string into multiple awaitable variables.
5
5
  Author-email: "Johannes A.I. Unruh" <johannes@unruh.ai>
6
6
  License: MIT License