pyfcstm 0.1.0__py3-none-any.whl → 0.1.2__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.
pyfcstm/config/meta.py CHANGED
@@ -7,7 +7,7 @@ Overview:
7
7
  __TITLE__ = 'pyfcstm'
8
8
 
9
9
  #: Version of this project.
10
- __VERSION__ = '0.1.0'
10
+ __VERSION__ = '0.1.2'
11
11
 
12
12
  #: Short description of the project, will be included in ``setup.py``.
13
13
  __DESCRIPTION__ = ('A Python framework for parsing finite state machine DSL and '
pyfcstm/model/model.py CHANGED
@@ -38,6 +38,8 @@ __all__ = [
38
38
  'parse_dsl_node_to_state_machine',
39
39
  ]
40
40
 
41
+ from ..utils import sequence_safe
42
+
41
43
 
42
44
  @dataclass
43
45
  class Operation(AstExportable):
@@ -877,18 +879,27 @@ class State(AstExportable, PlantUMLExportable):
877
879
  :return: PlantUML representation of the state
878
880
  :rtype: str
879
881
  """
882
+
883
+ def _name_safe(sub_state: Optional[str] = None):
884
+ subpath = [*self.path]
885
+ if sub_state is not None:
886
+ subpath.append(sub_state)
887
+ return sequence_safe(subpath)
888
+
880
889
  with io.StringIO() as sf:
881
890
  if self.is_leaf_state:
882
- print(f'state {self.name}', file=sf, end='')
891
+ print(f'state {json.dumps(self.name)} as {_name_safe()}', file=sf, end='')
883
892
  else:
884
- print(f'state {self.name} {{', file=sf)
893
+ print(f'state {json.dumps(self.name)} as {_name_safe()} {{', file=sf)
885
894
  for state in self.substates.values():
886
895
  print(indent(state.to_plantuml(), prefix=' '), file=sf)
887
896
  for trans in self.transitions:
888
897
  with io.StringIO() as tf:
889
- print('[*]' if trans.from_state is dsl_nodes.INIT_STATE else trans.from_state, file=tf, end='')
898
+ print('[*]' if trans.from_state is dsl_nodes.INIT_STATE
899
+ else _name_safe(trans.from_state), file=tf, end='')
890
900
  print(' --> ', file=tf, end='')
891
- print('[*]' if trans.to_state is dsl_nodes.EXIT_STATE else trans.to_state, file=tf, end='')
901
+ print('[*]' if trans.to_state is dsl_nodes.EXIT_STATE
902
+ else _name_safe(trans.to_state), file=tf, end='')
892
903
 
893
904
  if trans.event is not None:
894
905
  print(f' : {".".join(list(trans.event.path[len(self.path):]))}', file=tf, end='')
@@ -920,7 +931,7 @@ class State(AstExportable, PlantUMLExportable):
920
931
  for during_aspect_item in self.on_during_aspects:
921
932
  print(during_aspect_item.to_ast_node(), file=tf)
922
933
  text = json.dumps(tf.getvalue().rstrip()).strip("\"")
923
- print(f'{self.name} : {text}', file=sf, end='')
934
+ print(f'{_name_safe()} : {text}', file=sf, end='')
924
935
 
925
936
  return sf.getvalue()
926
937
 
@@ -1021,8 +1032,8 @@ class StateMachine(AstExportable, PlantUMLExportable):
1021
1032
  print('end note', file=sf)
1022
1033
  print('', file=sf)
1023
1034
  print(self.root_state.to_plantuml(), file=sf)
1024
- print(f'[*] --> {self.root_state.name}', file=sf)
1025
- print(f'{self.root_state.name} --> [*]', file=sf)
1035
+ print(f'[*] --> {sequence_safe(self.root_state.path)}', file=sf)
1036
+ print(f'{sequence_safe(self.root_state.path)} --> [*]', file=sf)
1026
1037
  print('@enduml', file=sf, end='')
1027
1038
  return sf.getvalue()
1028
1039
 
@@ -1147,7 +1158,7 @@ def parse_dsl_node_to_state_machine(dnode: dsl_nodes.StateMachineDSLProgram) ->
1147
1158
 
1148
1159
  transitions = current_state.transitions
1149
1160
  for subnode in node.substates:
1150
- _inner_force_transitions = [*force_transitions]
1161
+ _inner_force_transitions = []
1151
1162
  for from_state, to_state, my_event_id, trans_event, condition_expr, guard in force_transition_tuples_to_inherit:
1152
1163
  if from_state is dsl_nodes.ALL or from_state == subnode.name:
1153
1164
  transitions.append(Transition(
pyfcstm/utils/__init__.py CHANGED
@@ -3,5 +3,6 @@ from .decode import auto_decode
3
3
  from .doc import format_multiline_comment
4
4
  from .jinja2 import add_builtins_to_env, add_settings_for_env
5
5
  from .json import IJsonOp
6
+ from .safe import sequence_safe
6
7
  from .text import normalize, to_identifier
7
8
  from .validate import ValidationError, ModelValidationError, IValidatable
pyfcstm/utils/safe.py ADDED
@@ -0,0 +1,41 @@
1
+ """
2
+ Utility module for creating safe sequence identifiers.
3
+
4
+ This module provides functionality to convert sequences of strings into safe,
5
+ underscore-separated identifiers. It's particularly useful for generating
6
+ consistent naming conventions from potentially inconsistent input strings.
7
+
8
+ The main use case is to take a collection of string segments that may use
9
+ different naming conventions (CamelCase, snake_case, kebab-case, etc.) and
10
+ normalize them into a consistent, safe identifier format using underscores
11
+ as separators.
12
+ """
13
+
14
+ import re
15
+ from typing import Iterable
16
+
17
+ from hbutils.string import underscore
18
+
19
+
20
+ def sequence_safe(segments: Iterable[str]) -> str:
21
+ """
22
+ Convert a sequence of strings into a safe underscore-separated identifier.
23
+
24
+ This function takes a sequence of strings, converts each to underscore format,
25
+ normalizes multiple consecutive underscores to single underscores, and joins
26
+ them with double underscores ('__'). This is useful for creating consistent
27
+ identifiers from potentially inconsistent input strings.
28
+
29
+ :param segments: A sequence of strings to be converted into a safe identifier.
30
+ :type segments: Iterable[str]
31
+
32
+ :return: A safe underscore-separated identifier string.
33
+ :rtype: str
34
+
35
+ Example::
36
+ >>> sequence_safe(['CamelCase', 'snake_case', 'kebab-case'])
37
+ 'camel_case__snake_case__kebab_case'
38
+ >>> sequence_safe(['Hello World', 'Test___String'])
39
+ 'hello_world__test_string'
40
+ """
41
+ return '__'.join(map(lambda x: re.sub(r'_+', '_', underscore(x)), segments))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyfcstm
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: A Python framework for parsing finite state machine DSL and generating executable code in multiple target languages.
5
5
  Home-page: https://github.com/hansbug/pyfcstm
6
6
  Author: HansBug
@@ -1,7 +1,7 @@
1
1
  pyfcstm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  pyfcstm/__main__.py,sha256=rqAJpNJgf8R-OZnKecjYyCrK_hJcQhHaO0UL6Vb92-8,75
3
3
  pyfcstm/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- pyfcstm/config/meta.py,sha256=z4hf_T3kF1MS6kkQlF4QsxASIvNRh93TTGLkjUQZnNQ,534
4
+ pyfcstm/config/meta.py,sha256=aaBszpb_wRXoEVbFncNHuD9R0bLJbUlWeCyBhWpTTUk,534
5
5
  pyfcstm/dsl/__init__.py,sha256=3GMEILDRArhkjz0vQPHOk_eiby74H94TOa3o-Tpo4x0,349
6
6
  pyfcstm/dsl/error.py,sha256=BEaroPj98Q8J12IT73rfPeb9y0TXjPG6llDo5GiqRIU,8878
7
7
  pyfcstm/dsl/listener.py,sha256=9J8QETMu40HxT20ZOJ4c9QWY7X_Y6AbEgkzoD-xTAg4,19633
@@ -25,23 +25,24 @@ pyfcstm/entry/plantuml.py,sha256=uZUZ_kxhxinh8Jw6nf0e4c2C14kfqH5eeRS3bbCDRbc,266
25
25
  pyfcstm/model/__init__.py,sha256=aJ76DOX21iXRJN2xwsH7CiEG7iPkpDJMXKvEh9Xb9Q4,93
26
26
  pyfcstm/model/base.py,sha256=3H6Sf9uTfAZUNemSmR4L1aoSICG42EcrVncgQDZNAXY,1761
27
27
  pyfcstm/model/expr.py,sha256=X3eyOYMeZ66LdD0ZpwDjDRQUQrkpXtpSWLY9TILFzSI,18908
28
- pyfcstm/model/model.py,sha256=fiZ69V3CGUBbCxV4gkRrWECTOsXaJ9Ful3adHlIv8tk,56066
28
+ pyfcstm/model/model.py,sha256=hIxzlFjViZo7C9nwP7NAtGD6USedmK1k69QJFZbYLTw,56476
29
29
  pyfcstm/render/__init__.py,sha256=Bettq3kIoswqSZQSxjQciMrmRZqkn5noaKoQO9d8Jlw,153
30
30
  pyfcstm/render/env.py,sha256=pjZnlvYLL8sA9lZupKtIHijrHOiAWBeBU_ytNYLxz1w,1106
31
31
  pyfcstm/render/expr.py,sha256=sT7uazQuEFrAFHBSTV0FviubNIYP-CTjhNhd4dO96Fo,7551
32
32
  pyfcstm/render/func.py,sha256=FZlQiKxKpOomH83FDqYYoeeclXlmm07zHYJk8MN5Cws,2663
33
33
  pyfcstm/render/render.py,sha256=FmhHJvoIwWFGpm-KqDqybadj9pZbo7-bIiNxnyBF2Fc,11577
34
- pyfcstm/utils/__init__.py,sha256=9Bhh0epIZ_zL3ynzN7LUG9ts3aBcSXMbxSr_fRCJIkg,314
34
+ pyfcstm/utils/__init__.py,sha256=FwtqP21-Uzj_2ocvdKTJ9ex-qJ_hcnyhWKj_vFYd6pg,346
35
35
  pyfcstm/utils/binary.py,sha256=6AnX6Hx4JFRHl0Y1A6OJ1b_1-QtzaajEywp0h-a4kbs,1196
36
36
  pyfcstm/utils/decode.py,sha256=V9WYt9_db_ddIB3PiSsGPPAO_aAeHinNRvA3W5jO6XM,3636
37
37
  pyfcstm/utils/doc.py,sha256=CNGQoxTl33KEAnEXl_sr4I97zNARaAa2IwKKt5IC1MA,1905
38
38
  pyfcstm/utils/jinja2.py,sha256=9lJFnsxfzTfc9Wj1twhk3e6aFgRzBW-mbhdOVudNcKw,4321
39
39
  pyfcstm/utils/json.py,sha256=WPubB5ObTNT8eEyGV3DcgFE8BuYxJUO8xYPx5_kvvCQ,3732
40
+ pyfcstm/utils/safe.py,sha256=PT5WbzRlQqbaxYVqPB5f6mIhJXb3sa8JBwPcqXnuU9U,1565
40
41
  pyfcstm/utils/text.py,sha256=wb4vIWB3mLne1R64x_MIS5qsIlGQ6cGCUVcbPlV21Hw,2895
41
42
  pyfcstm/utils/validate.py,sha256=87k1B-gzYd-mZP2N5-nsC8OeLZsfNTOCjp_5LUgsaxw,3129
42
- pyfcstm-0.1.0.dist-info/LICENSE,sha256=pWgb-bBdsU2Gd2kwAXxketnm5W_2u8_fIeWEgojfrxs,7651
43
- pyfcstm-0.1.0.dist-info/METADATA,sha256=UD0bt8g15Yl44cOudHA7YEX6O6ghsCT6wGhHnY9U5J8,13742
44
- pyfcstm-0.1.0.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
45
- pyfcstm-0.1.0.dist-info/entry_points.txt,sha256=Jh9a4hY-nMh5VTiuIBiZcM403biCHOwXk5hKNBr3Eok,53
46
- pyfcstm-0.1.0.dist-info/top_level.txt,sha256=0VZTj6MqIhOSyoQLYUk1inV0P34VgetNZIKrzj-HNqo,8
47
- pyfcstm-0.1.0.dist-info/RECORD,,
43
+ pyfcstm-0.1.2.dist-info/LICENSE,sha256=pWgb-bBdsU2Gd2kwAXxketnm5W_2u8_fIeWEgojfrxs,7651
44
+ pyfcstm-0.1.2.dist-info/METADATA,sha256=EFjxrNds-RricBfU83I1ykUuXDjO89fgzRfvkDHKc_w,13742
45
+ pyfcstm-0.1.2.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
46
+ pyfcstm-0.1.2.dist-info/entry_points.txt,sha256=Jh9a4hY-nMh5VTiuIBiZcM403biCHOwXk5hKNBr3Eok,53
47
+ pyfcstm-0.1.2.dist-info/top_level.txt,sha256=0VZTj6MqIhOSyoQLYUk1inV0P34VgetNZIKrzj-HNqo,8
48
+ pyfcstm-0.1.2.dist-info/RECORD,,