pyfcstm 0.1.0__tar.gz → 0.1.2__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 (59) hide show
  1. {pyfcstm-0.1.0/pyfcstm.egg-info → pyfcstm-0.1.2}/PKG-INFO +8 -8
  2. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/config/meta.py +1 -1
  3. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/model/model.py +19 -8
  4. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/utils/__init__.py +1 -0
  5. pyfcstm-0.1.2/pyfcstm/utils/safe.py +41 -0
  6. {pyfcstm-0.1.0 → pyfcstm-0.1.2/pyfcstm.egg-info}/PKG-INFO +8 -8
  7. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm.egg-info/SOURCES.txt +1 -0
  8. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/LICENSE +0 -0
  9. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/MANIFEST.in +0 -0
  10. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/README.md +0 -0
  11. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/__init__.py +0 -0
  12. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/__main__.py +0 -0
  13. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/config/__init__.py +0 -0
  14. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/dsl/__init__.py +0 -0
  15. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/dsl/error.py +0 -0
  16. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/dsl/grammar/Grammar.g4 +0 -0
  17. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/dsl/grammar/Grammar.interp +0 -0
  18. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/dsl/grammar/Grammar.tokens +0 -0
  19. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/dsl/grammar/GrammarLexer.interp +0 -0
  20. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/dsl/grammar/GrammarLexer.py +0 -0
  21. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/dsl/grammar/GrammarLexer.tokens +0 -0
  22. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/dsl/grammar/GrammarListener.py +0 -0
  23. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/dsl/grammar/GrammarParser.py +0 -0
  24. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/dsl/grammar/__init__.py +0 -0
  25. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/dsl/listener.py +0 -0
  26. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/dsl/node.py +0 -0
  27. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/dsl/parse.py +0 -0
  28. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/entry/__init__.py +0 -0
  29. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/entry/base.py +0 -0
  30. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/entry/cli.py +0 -0
  31. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/entry/dispatch.py +0 -0
  32. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/entry/generate.py +0 -0
  33. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/entry/plantuml.py +0 -0
  34. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/model/__init__.py +0 -0
  35. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/model/base.py +0 -0
  36. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/model/expr.py +0 -0
  37. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/render/__init__.py +0 -0
  38. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/render/env.py +0 -0
  39. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/render/expr.py +0 -0
  40. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/render/func.py +0 -0
  41. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/render/render.py +0 -0
  42. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/utils/binary.py +0 -0
  43. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/utils/decode.py +0 -0
  44. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/utils/doc.py +0 -0
  45. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/utils/jinja2.py +0 -0
  46. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/utils/json.py +0 -0
  47. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/utils/text.py +0 -0
  48. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm/utils/validate.py +0 -0
  49. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm.egg-info/dependency_links.txt +0 -0
  50. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm.egg-info/entry_points.txt +0 -0
  51. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm.egg-info/requires.txt +0 -0
  52. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/pyfcstm.egg-info/top_level.txt +0 -0
  53. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/requirements-build.txt +0 -0
  54. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/requirements-dev.txt +0 -0
  55. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/requirements-doc.txt +0 -0
  56. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/requirements-test.txt +0 -0
  57. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/requirements.txt +0 -0
  58. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/setup.cfg +0 -0
  59. {pyfcstm-0.1.0 → pyfcstm-0.1.2}/setup.py +0 -0
@@ -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
@@ -91,13 +91,6 @@ Requires-Dist: ipykernel>=6.15; extra == "doc"
91
91
  Requires-Dist: py-cpuinfo>=8.0.0; extra == "doc"
92
92
  Requires-Dist: click>=7.0.0; extra == "doc"
93
93
  Requires-Dist: pandas; extra == "doc"
94
- Provides-Extra: build
95
- Requires-Dist: pyinstaller>=4.7; extra == "build"
96
- Requires-Dist: setuptools; extra == "build"
97
- Requires-Dist: hbutils; extra == "build"
98
- Provides-Extra: dev
99
- Requires-Dist: ruff; extra == "dev"
100
- Requires-Dist: antlr4-python3-runtime==4.9.3; extra == "dev"
101
94
  Provides-Extra: test
102
95
  Requires-Dist: coverage>=5; extra == "test"
103
96
  Requires-Dist: mock>=4.0.3; extra == "test"
@@ -114,6 +107,13 @@ Requires-Dist: easydict<2,>=1.7; extra == "test"
114
107
  Requires-Dist: testtools>=2; extra == "test"
115
108
  Requires-Dist: where>=1.0.2; extra == "test"
116
109
  Requires-Dist: natsort; extra == "test"
110
+ Provides-Extra: dev
111
+ Requires-Dist: ruff; extra == "dev"
112
+ Requires-Dist: antlr4-python3-runtime==4.9.3; extra == "dev"
113
+ Provides-Extra: build
114
+ Requires-Dist: pyinstaller>=4.7; extra == "build"
115
+ Requires-Dist: setuptools; extra == "build"
116
+ Requires-Dist: hbutils; extra == "build"
117
117
 
118
118
  # pyfcstm
119
119
 
@@ -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 '
@@ -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(
@@ -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
@@ -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
@@ -91,13 +91,6 @@ Requires-Dist: ipykernel>=6.15; extra == "doc"
91
91
  Requires-Dist: py-cpuinfo>=8.0.0; extra == "doc"
92
92
  Requires-Dist: click>=7.0.0; extra == "doc"
93
93
  Requires-Dist: pandas; extra == "doc"
94
- Provides-Extra: build
95
- Requires-Dist: pyinstaller>=4.7; extra == "build"
96
- Requires-Dist: setuptools; extra == "build"
97
- Requires-Dist: hbutils; extra == "build"
98
- Provides-Extra: dev
99
- Requires-Dist: ruff; extra == "dev"
100
- Requires-Dist: antlr4-python3-runtime==4.9.3; extra == "dev"
101
94
  Provides-Extra: test
102
95
  Requires-Dist: coverage>=5; extra == "test"
103
96
  Requires-Dist: mock>=4.0.3; extra == "test"
@@ -114,6 +107,13 @@ Requires-Dist: easydict<2,>=1.7; extra == "test"
114
107
  Requires-Dist: testtools>=2; extra == "test"
115
108
  Requires-Dist: where>=1.0.2; extra == "test"
116
109
  Requires-Dist: natsort; extra == "test"
110
+ Provides-Extra: dev
111
+ Requires-Dist: ruff; extra == "dev"
112
+ Requires-Dist: antlr4-python3-runtime==4.9.3; extra == "dev"
113
+ Provides-Extra: build
114
+ Requires-Dist: pyinstaller>=4.7; extra == "build"
115
+ Requires-Dist: setuptools; extra == "build"
116
+ Requires-Dist: hbutils; extra == "build"
117
117
 
118
118
  # pyfcstm
119
119
 
@@ -52,5 +52,6 @@ pyfcstm/utils/decode.py
52
52
  pyfcstm/utils/doc.py
53
53
  pyfcstm/utils/jinja2.py
54
54
  pyfcstm/utils/json.py
55
+ pyfcstm/utils/safe.py
55
56
  pyfcstm/utils/text.py
56
57
  pyfcstm/utils/validate.py
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes