jmux 0.0.1__py3-none-any.whl → 0.0.3__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.
jmux/demux.py CHANGED
@@ -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,9 @@ class JMux(ABC):
421
422
  case None:
422
423
  match self._pda.state:
423
424
  case S.START:
424
- if ch in OBJECT_OPEN:
425
+ if ch in JSON_WHITESPACE:
426
+ pass
427
+ elif ch in OBJECT_OPEN:
425
428
  self._pda.push(M.ROOT)
426
429
  self._pda.set_state(S.EXPECT_KEY)
427
430
  else:
@@ -432,13 +435,16 @@ class JMux(ABC):
432
435
  "JSON must start with '{' character.",
433
436
  )
434
437
  case S.END:
435
- raise ObjectAlreadyClosedError(
436
- object_name=self.__class__.__name__,
437
- message=(
438
- "Cannot feed more characters to closed JMux "
439
- f"object, got '{ch}'"
440
- ),
441
- )
438
+ if ch in JSON_WHITESPACE:
439
+ pass
440
+ else:
441
+ raise ObjectAlreadyClosedError(
442
+ object_name=self.__class__.__name__,
443
+ message=(
444
+ "Cannot feed more characters to closed JMux "
445
+ f"object, got '{ch}'"
446
+ ),
447
+ )
442
448
  case _:
443
449
  raise UnexpectedStateError(
444
450
  self._pda.stack,
@@ -453,7 +459,7 @@ class JMux(ABC):
453
459
  case M.ROOT:
454
460
  match self._pda.state:
455
461
  case S.EXPECT_KEY:
456
- if is_json_whitespace(ch):
462
+ if ch in JSON_WHITESPACE:
457
463
  pass
458
464
  elif ch == '"':
459
465
  self._pda.set_state(S.PARSING_KEY)
@@ -480,7 +486,7 @@ class JMux(ABC):
480
486
  self._decoder.push(ch)
481
487
 
482
488
  case S.EXPECT_COLON:
483
- if is_json_whitespace(ch):
489
+ if ch in JSON_WHITESPACE:
484
490
  pass
485
491
  elif ch in COLON:
486
492
  self._pda.set_state(S.EXPECT_VALUE)
@@ -493,7 +499,7 @@ class JMux(ABC):
493
499
  )
494
500
 
495
501
  case S.EXPECT_VALUE:
496
- if is_json_whitespace(ch):
502
+ if ch in JSON_WHITESPACE:
497
503
  pass
498
504
  elif res := await self._handle_common__expect_value(ch):
499
505
  if (
@@ -545,20 +551,20 @@ class JMux(ABC):
545
551
  ):
546
552
  await self._sink.emit(maybe_char)
547
553
 
548
- case _ if self._pda.state in PRIMITIVE_STATES:
549
- if ch not in COMMA | OBJECT_CLOSE:
550
- self._assert_primitive_character_allowed_in_state(ch)
551
- self._decoder.push(ch)
552
- else:
554
+ case _ if self._pda.state in PARSING_PRIMITIVE_STATES:
555
+ if ch in COMMA | OBJECT_CLOSE | JSON_WHITESPACE:
553
556
  await self._parse_primitive()
554
557
  await self._sink.close()
555
558
  self._decoder.reset()
556
559
  self._pda.set_state(S.EXPECT_KEY)
557
560
  if ch in OBJECT_CLOSE:
558
561
  await self._finalize()
562
+ else:
563
+ self._assert_primitive_character_allowed_in_state(ch)
564
+ self._decoder.push(ch)
559
565
 
560
566
  case S.EXPECT_COMMA_OR_EOC:
561
- if is_json_whitespace(ch):
567
+ if ch in JSON_WHITESPACE:
562
568
  pass
563
569
  elif ch in COMMA:
564
570
  self._pda.set_state(S.EXPECT_KEY)
@@ -591,7 +597,7 @@ class JMux(ABC):
591
597
 
592
598
  match self._pda.state:
593
599
  case S.EXPECT_VALUE:
594
- if is_json_whitespace(ch):
600
+ if ch in JSON_WHITESPACE:
595
601
  pass
596
602
  elif await self._handle_common__expect_value(ch):
597
603
  pass
@@ -633,20 +639,20 @@ class JMux(ABC):
633
639
  else:
634
640
  self._decoder.push(ch)
635
641
 
636
- case _ if self._pda.state in PRIMITIVE_STATES:
637
- if ch not in COMMA | ARRAY_CLOSE:
638
- self._assert_primitive_character_allowed_in_state(ch)
639
- self._decoder.push(ch)
640
- else:
642
+ case _ if self._pda.state in PARSING_PRIMITIVE_STATES:
643
+ if ch in COMMA | ARRAY_CLOSE | JSON_WHITESPACE:
641
644
  await self._parse_primitive()
642
645
  self._decoder.reset()
643
646
  if ch in COMMA:
644
647
  self._pda.set_state(S.EXPECT_VALUE)
645
648
  elif ch in ARRAY_CLOSE:
646
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)
647
653
 
648
654
  case S.EXPECT_COMMA_OR_EOC:
649
- if is_json_whitespace(ch):
655
+ if ch in JSON_WHITESPACE:
650
656
  pass
651
657
  elif ch in COMMA:
652
658
  self._pda.set_state(S.EXPECT_VALUE)
@@ -676,8 +682,16 @@ class JMux(ABC):
676
682
  self._pda.state,
677
683
  "State in object context must be 'parsing_object'",
678
684
  )
679
- 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:
680
690
  self._pda.pop()
691
+ if self._pda.top is M.OBJECT:
692
+ await self._sink.forward_char(ch)
693
+ return
694
+
681
695
  if self._pda.top is M.ROOT:
682
696
  await self._sink.close()
683
697
  self._pda.set_state(S.EXPECT_COMMA_OR_EOC)
@@ -694,7 +708,8 @@ class JMux(ABC):
694
708
  )
695
709
  await self._sink.emit(None)
696
710
  elif self._pda.state is S.PARSING_BOOLEAN:
697
- 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)
698
713
  else:
699
714
  try:
700
715
  buffer = self._decoder.buffer
jmux/helpers.py CHANGED
@@ -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]]:
jmux/types.py CHANGED
@@ -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.1
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
@@ -0,0 +1,13 @@
1
+ jmux/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ jmux/awaitable.py,sha256=gceBygIf3fAIWLsN1lWxsz9ExWNasDuk1WaGz8d9FAc,8427
3
+ jmux/decoder.py,sha256=Y6KVryRDLvGV5nBsneXpTvC0WUGhR5Z89Dvqz4HMAgg,1562
4
+ jmux/demux.py,sha256=0dKIQibyDQkijuIcT53Za1L2DZbC_Ll0_1mhroqHg9I,35516
5
+ jmux/error.py,sha256=VZJYivt8RPfjcF2bs-T7_UkH3dVA3xH-xGbZggQV14k,4665
6
+ jmux/helpers.py,sha256=DQyPeuwx3AR65aHrET7xpSbfTLTC7ji3CyicyEhqJpk,2226
7
+ jmux/pda.py,sha256=81gnh0eWGsgd_SrHkqjRQy_KkOSlBf5nor7pqKGgYjw,791
8
+ jmux/types.py,sha256=5Ox01s-rGMQ1xGX8NRNBlyWtxvGKwnt9bjexXdESSYc,1233
9
+ jmux-0.0.3.dist-info/licenses/LICENSE,sha256=y0qnwaAe4bEqzNPyq4M_VZA2I2mQly8MawajyZhqw0k,1169
10
+ jmux-0.0.3.dist-info/METADATA,sha256=ZSi9Y5l5FsyaJuTW3N2K199mCNfkMe8_FLmxjIEfSAA,13330
11
+ jmux-0.0.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
+ jmux-0.0.3.dist-info/top_level.txt,sha256=TF2N6kHqLghfOkCiNlCueMDX4l5rPn_5MSPNtYrS1-o,5
13
+ jmux-0.0.3.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- jmux/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- jmux/awaitable.py,sha256=gceBygIf3fAIWLsN1lWxsz9ExWNasDuk1WaGz8d9FAc,8427
3
- jmux/decoder.py,sha256=Y6KVryRDLvGV5nBsneXpTvC0WUGhR5Z89Dvqz4HMAgg,1562
4
- jmux/demux.py,sha256=ouhu2PIJkaEIsToNfDhJWGQYjFYULjqFSEX5ElmAjPs,34861
5
- jmux/error.py,sha256=VZJYivt8RPfjcF2bs-T7_UkH3dVA3xH-xGbZggQV14k,4665
6
- jmux/helpers.py,sha256=6y33RohUGVvGGaAREyRQTmEWfgV4w295SyqDwIMnUNs,1982
7
- jmux/pda.py,sha256=81gnh0eWGsgd_SrHkqjRQy_KkOSlBf5nor7pqKGgYjw,791
8
- jmux/types.py,sha256=V63wMx1I7l_P83JAqzOQ7H7B-xKrNUuGshJ3NjKsdeQ,1192
9
- jmux-0.0.1.dist-info/licenses/LICENSE,sha256=y0qnwaAe4bEqzNPyq4M_VZA2I2mQly8MawajyZhqw0k,1169
10
- jmux-0.0.1.dist-info/METADATA,sha256=Y4E3GeCPbNYvUv6B877m_c7DZUXlZO5voWCbxXVtwSg,13330
11
- jmux-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
- jmux-0.0.1.dist-info/top_level.txt,sha256=TF2N6kHqLghfOkCiNlCueMDX4l5rPn_5MSPNtYrS1-o,5
13
- jmux-0.0.1.dist-info/RECORD,,
File without changes