PyDMConverter 1.0.3__tar.gz → 1.0.4__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 (145) hide show
  1. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/.gitignore +4 -0
  2. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/PKG-INFO +8 -3
  3. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/PyDMConverter.egg-info/PKG-INFO +8 -3
  4. pydmconverter-1.0.4/PyDMConverter.egg-info/SOURCES.txt +142 -0
  5. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/PyDMConverter.egg-info/requires.txt +8 -2
  6. pydmconverter-1.0.4/PyDMConverter.egg-info/scm_file_list.json +138 -0
  7. pydmconverter-1.0.4/PyDMConverter.egg-info/scm_version.json +8 -0
  8. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/src/model/options_model.py +6 -0
  9. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/src/view/main_window.py +20 -3
  10. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/src/view/options_window.py +9 -0
  11. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/__main__.py +76 -7
  12. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/custom_types.py +3 -2
  13. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/edm/converter.py +3 -2
  14. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/edm/converter_helpers.py +47 -85
  15. pydmconverter-1.0.4/pydmconverter/edm/edm_qt.py +101 -0
  16. pydmconverter-1.0.4/pydmconverter/edm/ir_adapter.py +195 -0
  17. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/edm/parser.py +5 -2
  18. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/edm/parser_helpers.py +218 -24
  19. pydmconverter-1.0.4/pydmconverter/ir/__init__.py +42 -0
  20. pydmconverter-1.0.4/pydmconverter/ir/base.py +27 -0
  21. pydmconverter-1.0.4/pydmconverter/ir/builder.py +197 -0
  22. pydmconverter-1.0.4/pydmconverter/ir/data/screen-ir.schema.json +424 -0
  23. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/.beaver-snapshot-sha +1 -0
  24. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/absolute-canvas.json +35 -0
  25. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/embedded-display.json +55 -0
  26. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/frame.json +52 -0
  27. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/group-box.json +44 -0
  28. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/image-view.json +51 -0
  29. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/pv-button.json +57 -0
  30. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/pv-byte-led.json +58 -0
  31. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/pv-checkbox.json +55 -0
  32. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/pv-enum-combobox.json +49 -0
  33. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/pv-label.json +72 -0
  34. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/pv-led.json +50 -0
  35. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/pv-progress-bar.json +62 -0
  36. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/pv-radio-group.json +42 -0
  37. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/pv-slider.json +58 -0
  38. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/pv-text-input.json +57 -0
  39. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/regular-button.json +49 -0
  40. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/related-display-button.json +60 -0
  41. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/scroll-area.json +52 -0
  42. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/tabs.json +50 -0
  43. pydmconverter-1.0.4/pydmconverter/ir/data/widget-registry/text-label.json +55 -0
  44. pydmconverter-1.0.4/pydmconverter/ir/emit.py +51 -0
  45. pydmconverter-1.0.4/pydmconverter/ir/fox.py +65 -0
  46. pydmconverter-1.0.4/pydmconverter/ir/ids.py +73 -0
  47. pydmconverter-1.0.4/pydmconverter/ir/macros.py +34 -0
  48. pydmconverter-1.0.4/pydmconverter/ir/model.py +177 -0
  49. pydmconverter-1.0.4/pydmconverter/ir/registry.py +120 -0
  50. pydmconverter-1.0.4/pydmconverter/ir/schema.py +62 -0
  51. pydmconverter-1.0.4/pydmconverter/ir/source.py +75 -0
  52. pydmconverter-1.0.4/pydmconverter/ir/transforms.py +158 -0
  53. pydmconverter-1.0.4/pydmconverter/react.py +113 -0
  54. pydmconverter-1.0.4/pydmconverter/ui/__init__.py +6 -0
  55. pydmconverter-1.0.4/pydmconverter/ui/ir_adapter.py +181 -0
  56. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/widgets.py +38 -0
  57. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/widgets_helpers.py +29 -11
  58. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pyproject.toml +13 -4
  59. pydmconverter-1.0.4/tests/edm/fixtures/p0_min.edl +74 -0
  60. pydmconverter-1.0.4/tests/edm/fixtures/p0_vis.edl +62 -0
  61. pydmconverter-1.0.4/tests/edm/fixtures/p1_widgets.edl +47 -0
  62. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/tests/edm/test_converter.py +92 -0
  63. pydmconverter-1.0.4/tests/edm/test_ir_adapter.py +68 -0
  64. pydmconverter-1.0.4/tests/edm/test_p1_widgets.py +26 -0
  65. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/tests/edm/test_parser_helpers.py +104 -4
  66. pydmconverter-1.0.4/tests/edm/test_visibility_rules.py +50 -0
  67. pydmconverter-1.0.4/tests/ir/__init__.py +0 -0
  68. pydmconverter-1.0.4/tests/ir/conftest.py +69 -0
  69. pydmconverter-1.0.4/tests/ir/test_ir_builder.py +186 -0
  70. pydmconverter-1.0.4/tests/ir/test_ir_emit.py +50 -0
  71. pydmconverter-1.0.4/tests/ir/test_ir_fox.py +41 -0
  72. pydmconverter-1.0.4/tests/ir/test_ir_ids.py +38 -0
  73. pydmconverter-1.0.4/tests/ir/test_ir_model.py +88 -0
  74. pydmconverter-1.0.4/tests/ir/test_ir_registry.py +74 -0
  75. pydmconverter-1.0.4/tests/ir/test_ir_schema.py +25 -0
  76. pydmconverter-1.0.4/tests/ir/test_ir_transforms.py +86 -0
  77. pydmconverter-1.0.4/tests/test_headless_import.py +35 -0
  78. pydmconverter-1.0.4/tests/test_options_model.py +38 -0
  79. pydmconverter-1.0.4/tests/test_react.py +72 -0
  80. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/tests/test_widgets.py +41 -0
  81. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/tests/test_widgets_helpers.py +56 -0
  82. pydmconverter-1.0.4/tests/ui/__init__.py +0 -0
  83. pydmconverter-1.0.4/tests/ui/fixtures/p0_min.ui +75 -0
  84. pydmconverter-1.0.4/tests/ui/fixtures/p1_widgets.ui +46 -0
  85. pydmconverter-1.0.4/tests/ui/test_ir_adapter.py +109 -0
  86. pydmconverter-1.0.4/tests/ui/test_p1_widgets.py +50 -0
  87. pydmconverter-1.0.3/PyDMConverter.egg-info/SOURCES.txt +0 -77
  88. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  89. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  90. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/.github/workflows/gh-pages.yml +0 -0
  91. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/.github/workflows/lint.yml +0 -0
  92. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/.github/workflows/pypi_release.yml +0 -0
  93. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/.github/workflows/tests.yml +0 -0
  94. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/.pre-commit-config.yaml +0 -0
  95. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/LICENSE +0 -0
  96. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/PyDMConverter.egg-info/dependency_links.txt +0 -0
  97. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/PyDMConverter.egg-info/entry_points.txt +0 -0
  98. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/PyDMConverter.egg-info/top_level.txt +0 -0
  99. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/README.md +0 -0
  100. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/resources/file_minus.png +0 -0
  101. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/resources/file_plus.png +0 -0
  102. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/resources/file_x.png +0 -0
  103. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/resources/folder_plus.png +0 -0
  104. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/resources/folder_search.png +0 -0
  105. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/resources/play_circle_outline.png +0 -0
  106. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/resources/settings.png +0 -0
  107. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/src/model/__init__.py +0 -0
  108. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/src/model/app_model.py +0 -0
  109. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/src/view/__init__.py +0 -0
  110. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/src/view/file_select_widget.py +0 -0
  111. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/src/view/main_window.ui +0 -0
  112. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/app/src/view/output_select_dialog.py +0 -0
  113. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/docs/arguments.md +0 -0
  114. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/docs/images/pydmconverter.png +0 -0
  115. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/docs/index.md +0 -0
  116. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/docs/reference/custom_types.md +0 -0
  117. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/docs/reference/edm/converter.md +0 -0
  118. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/docs/reference/edm/converter_helpers.md +0 -0
  119. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/docs/reference/edm/menumux.md +0 -0
  120. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/docs/reference/edm/parser.md +0 -0
  121. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/docs/reference/edm/parser_helpers.md +0 -0
  122. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/docs/reference/index.md +0 -0
  123. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/docs/reference/pydm-converter-tool.md +0 -0
  124. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/docs/reference/widgets.md +0 -0
  125. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/docs/reference/widgets_helpers.md +0 -0
  126. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/docs/user_guide.md +0 -0
  127. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/environment.yml +0 -0
  128. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/examples/TEM_mapping.edl +0 -0
  129. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/examples/all_bsy0_main.edl +0 -0
  130. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/examples/all_bsy0_main_with_groups.edl +0 -0
  131. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/examples/prosilica.edl +0 -0
  132. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/mkdocs.yml +0 -0
  133. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/__init__.py +0 -0
  134. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/edm/__init__.py +0 -0
  135. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/edm/menumux.py +0 -0
  136. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/exceptions.py +0 -0
  137. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/launch_gui.sh +0 -0
  138. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/sites/__init__.py +0 -0
  139. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/pydmconverter/sites/slac.py +0 -0
  140. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/setup.cfg +0 -0
  141. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/tests/__init__.py +0 -0
  142. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/tests/edm/test_converter_helpers.py +0 -0
  143. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/tests/edm/test_parser.py +0 -0
  144. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/tests/test_main.py +0 -0
  145. {pydmconverter-1.0.3 → pydmconverter-1.0.4}/tests/test_sites.py +0 -0
@@ -119,3 +119,7 @@ ENV/
119
119
  .vscode/
120
120
 
121
121
  *.json
122
+
123
+ # Canopy IR data files (generated schema + vendored widget registry) are tracked assets
124
+ !pydmconverter/ir/data/*.json
125
+ !pydmconverter/ir/data/widget-registry/*.json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyDMConverter
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: converter to generate pydm .ui files from other display managers.
5
5
  Author: Devan Agrawal, Zach Domke, Ryan McClanahan, Alexander Ng, Logan Somoza, Alexandria Ikuma
6
6
  Author-email: Yekta Yazar <yazar@slac.stanford.edu>
@@ -692,13 +692,18 @@ Classifier: Topic :: Scientific/Engineering
692
692
  Requires-Python: >=3.10
693
693
  Description-Content-Type: text/markdown
694
694
  License-File: LICENSE
695
- Requires-Dist: pydm
696
- Requires-Dist: pyqt5
695
+ Requires-Dist: pydantic>=2
696
+ Requires-Dist: jsonschema>=4
697
+ Provides-Extra: gui
698
+ Requires-Dist: pydm; extra == "gui"
699
+ Requires-Dist: pyqt5; extra == "gui"
697
700
  Provides-Extra: dev
698
701
  Requires-Dist: pytest; extra == "dev"
699
702
  Requires-Dist: pytest-cov; extra == "dev"
700
703
  Requires-Dist: pytest-qt; extra == "dev"
701
704
  Requires-Dist: pytest-mock; extra == "dev"
705
+ Requires-Dist: pydm; extra == "dev"
706
+ Requires-Dist: pyqt5; extra == "dev"
702
707
  Dynamic: license-file
703
708
 
704
709
  # PyDM Converter
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyDMConverter
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: converter to generate pydm .ui files from other display managers.
5
5
  Author: Devan Agrawal, Zach Domke, Ryan McClanahan, Alexander Ng, Logan Somoza, Alexandria Ikuma
6
6
  Author-email: Yekta Yazar <yazar@slac.stanford.edu>
@@ -692,13 +692,18 @@ Classifier: Topic :: Scientific/Engineering
692
692
  Requires-Python: >=3.10
693
693
  Description-Content-Type: text/markdown
694
694
  License-File: LICENSE
695
- Requires-Dist: pydm
696
- Requires-Dist: pyqt5
695
+ Requires-Dist: pydantic>=2
696
+ Requires-Dist: jsonschema>=4
697
+ Provides-Extra: gui
698
+ Requires-Dist: pydm; extra == "gui"
699
+ Requires-Dist: pyqt5; extra == "gui"
697
700
  Provides-Extra: dev
698
701
  Requires-Dist: pytest; extra == "dev"
699
702
  Requires-Dist: pytest-cov; extra == "dev"
700
703
  Requires-Dist: pytest-qt; extra == "dev"
701
704
  Requires-Dist: pytest-mock; extra == "dev"
705
+ Requires-Dist: pydm; extra == "dev"
706
+ Requires-Dist: pyqt5; extra == "dev"
702
707
  Dynamic: license-file
703
708
 
704
709
  # PyDM Converter
@@ -0,0 +1,142 @@
1
+ .gitignore
2
+ .pre-commit-config.yaml
3
+ LICENSE
4
+ README.md
5
+ environment.yml
6
+ mkdocs.yml
7
+ pyproject.toml
8
+ .github/ISSUE_TEMPLATE/bug-report.yml
9
+ .github/ISSUE_TEMPLATE/feature-request.yml
10
+ .github/workflows/gh-pages.yml
11
+ .github/workflows/lint.yml
12
+ .github/workflows/pypi_release.yml
13
+ .github/workflows/tests.yml
14
+ PyDMConverter.egg-info/PKG-INFO
15
+ PyDMConverter.egg-info/SOURCES.txt
16
+ PyDMConverter.egg-info/dependency_links.txt
17
+ PyDMConverter.egg-info/entry_points.txt
18
+ PyDMConverter.egg-info/requires.txt
19
+ PyDMConverter.egg-info/scm_file_list.json
20
+ PyDMConverter.egg-info/scm_version.json
21
+ PyDMConverter.egg-info/top_level.txt
22
+ app/resources/file_minus.png
23
+ app/resources/file_plus.png
24
+ app/resources/file_x.png
25
+ app/resources/folder_plus.png
26
+ app/resources/folder_search.png
27
+ app/resources/play_circle_outline.png
28
+ app/resources/settings.png
29
+ app/src/model/__init__.py
30
+ app/src/model/app_model.py
31
+ app/src/model/options_model.py
32
+ app/src/view/__init__.py
33
+ app/src/view/file_select_widget.py
34
+ app/src/view/main_window.py
35
+ app/src/view/main_window.ui
36
+ app/src/view/options_window.py
37
+ app/src/view/output_select_dialog.py
38
+ docs/arguments.md
39
+ docs/index.md
40
+ docs/user_guide.md
41
+ docs/images/pydmconverter.png
42
+ docs/reference/custom_types.md
43
+ docs/reference/index.md
44
+ docs/reference/pydm-converter-tool.md
45
+ docs/reference/widgets.md
46
+ docs/reference/widgets_helpers.md
47
+ docs/reference/edm/converter.md
48
+ docs/reference/edm/converter_helpers.md
49
+ docs/reference/edm/menumux.md
50
+ docs/reference/edm/parser.md
51
+ docs/reference/edm/parser_helpers.md
52
+ examples/TEM_mapping.edl
53
+ examples/all_bsy0_main.edl
54
+ examples/all_bsy0_main_with_groups.edl
55
+ examples/prosilica.edl
56
+ pydmconverter/__init__.py
57
+ pydmconverter/__main__.py
58
+ pydmconverter/custom_types.py
59
+ pydmconverter/exceptions.py
60
+ pydmconverter/launch_gui.sh
61
+ pydmconverter/react.py
62
+ pydmconverter/widgets.py
63
+ pydmconverter/widgets_helpers.py
64
+ pydmconverter/edm/__init__.py
65
+ pydmconverter/edm/converter.py
66
+ pydmconverter/edm/converter_helpers.py
67
+ pydmconverter/edm/edm_qt.py
68
+ pydmconverter/edm/ir_adapter.py
69
+ pydmconverter/edm/menumux.py
70
+ pydmconverter/edm/parser.py
71
+ pydmconverter/edm/parser_helpers.py
72
+ pydmconverter/ir/__init__.py
73
+ pydmconverter/ir/base.py
74
+ pydmconverter/ir/builder.py
75
+ pydmconverter/ir/emit.py
76
+ pydmconverter/ir/fox.py
77
+ pydmconverter/ir/ids.py
78
+ pydmconverter/ir/macros.py
79
+ pydmconverter/ir/model.py
80
+ pydmconverter/ir/registry.py
81
+ pydmconverter/ir/schema.py
82
+ pydmconverter/ir/source.py
83
+ pydmconverter/ir/transforms.py
84
+ pydmconverter/ir/data/screen-ir.schema.json
85
+ pydmconverter/ir/data/widget-registry/.beaver-snapshot-sha
86
+ pydmconverter/ir/data/widget-registry/absolute-canvas.json
87
+ pydmconverter/ir/data/widget-registry/embedded-display.json
88
+ pydmconverter/ir/data/widget-registry/frame.json
89
+ pydmconverter/ir/data/widget-registry/group-box.json
90
+ pydmconverter/ir/data/widget-registry/image-view.json
91
+ pydmconverter/ir/data/widget-registry/pv-button.json
92
+ pydmconverter/ir/data/widget-registry/pv-byte-led.json
93
+ pydmconverter/ir/data/widget-registry/pv-checkbox.json
94
+ pydmconverter/ir/data/widget-registry/pv-enum-combobox.json
95
+ pydmconverter/ir/data/widget-registry/pv-label.json
96
+ pydmconverter/ir/data/widget-registry/pv-led.json
97
+ pydmconverter/ir/data/widget-registry/pv-progress-bar.json
98
+ pydmconverter/ir/data/widget-registry/pv-radio-group.json
99
+ pydmconverter/ir/data/widget-registry/pv-slider.json
100
+ pydmconverter/ir/data/widget-registry/pv-text-input.json
101
+ pydmconverter/ir/data/widget-registry/regular-button.json
102
+ pydmconverter/ir/data/widget-registry/related-display-button.json
103
+ pydmconverter/ir/data/widget-registry/scroll-area.json
104
+ pydmconverter/ir/data/widget-registry/tabs.json
105
+ pydmconverter/ir/data/widget-registry/text-label.json
106
+ pydmconverter/sites/__init__.py
107
+ pydmconverter/sites/slac.py
108
+ pydmconverter/ui/__init__.py
109
+ pydmconverter/ui/ir_adapter.py
110
+ tests/__init__.py
111
+ tests/test_headless_import.py
112
+ tests/test_main.py
113
+ tests/test_options_model.py
114
+ tests/test_react.py
115
+ tests/test_sites.py
116
+ tests/test_widgets.py
117
+ tests/test_widgets_helpers.py
118
+ tests/edm/test_converter.py
119
+ tests/edm/test_converter_helpers.py
120
+ tests/edm/test_ir_adapter.py
121
+ tests/edm/test_p1_widgets.py
122
+ tests/edm/test_parser.py
123
+ tests/edm/test_parser_helpers.py
124
+ tests/edm/test_visibility_rules.py
125
+ tests/edm/fixtures/p0_min.edl
126
+ tests/edm/fixtures/p0_vis.edl
127
+ tests/edm/fixtures/p1_widgets.edl
128
+ tests/ir/__init__.py
129
+ tests/ir/conftest.py
130
+ tests/ir/test_ir_builder.py
131
+ tests/ir/test_ir_emit.py
132
+ tests/ir/test_ir_fox.py
133
+ tests/ir/test_ir_ids.py
134
+ tests/ir/test_ir_model.py
135
+ tests/ir/test_ir_registry.py
136
+ tests/ir/test_ir_schema.py
137
+ tests/ir/test_ir_transforms.py
138
+ tests/ui/__init__.py
139
+ tests/ui/test_ir_adapter.py
140
+ tests/ui/test_p1_widgets.py
141
+ tests/ui/fixtures/p0_min.ui
142
+ tests/ui/fixtures/p1_widgets.ui
@@ -1,8 +1,14 @@
1
- pydm
2
- pyqt5
1
+ pydantic>=2
2
+ jsonschema>=4
3
3
 
4
4
  [dev]
5
5
  pytest
6
6
  pytest-cov
7
7
  pytest-qt
8
8
  pytest-mock
9
+ pydm
10
+ pyqt5
11
+
12
+ [gui]
13
+ pydm
14
+ pyqt5
@@ -0,0 +1,138 @@
1
+ {
2
+ "files": [
3
+ ".pre-commit-config.yaml",
4
+ "README.md",
5
+ "environment.yml",
6
+ "LICENSE",
7
+ "pyproject.toml",
8
+ "mkdocs.yml",
9
+ ".gitignore",
10
+ "docs/arguments.md",
11
+ "docs/user_guide.md",
12
+ "docs/index.md",
13
+ "docs/images/pydmconverter.png",
14
+ "docs/reference/widgets_helpers.md",
15
+ "docs/reference/widgets.md",
16
+ "docs/reference/custom_types.md",
17
+ "docs/reference/pydm-converter-tool.md",
18
+ "docs/reference/index.md",
19
+ "docs/reference/edm/parser_helpers.md",
20
+ "docs/reference/edm/parser.md",
21
+ "docs/reference/edm/menumux.md",
22
+ "docs/reference/edm/converter.md",
23
+ "docs/reference/edm/converter_helpers.md",
24
+ "tests/test_react.py",
25
+ "tests/test_headless_import.py",
26
+ "tests/__init__.py",
27
+ "tests/test_widgets_helpers.py",
28
+ "tests/test_widgets.py",
29
+ "tests/test_sites.py",
30
+ "tests/test_options_model.py",
31
+ "tests/test_main.py",
32
+ "tests/ir/test_ir_transforms.py",
33
+ "tests/ir/test_ir_fox.py",
34
+ "tests/ir/test_ir_ids.py",
35
+ "tests/ir/__init__.py",
36
+ "tests/ir/test_ir_model.py",
37
+ "tests/ir/test_ir_builder.py",
38
+ "tests/ir/conftest.py",
39
+ "tests/ir/test_ir_registry.py",
40
+ "tests/ir/test_ir_emit.py",
41
+ "tests/ir/test_ir_schema.py",
42
+ "tests/ui/__init__.py",
43
+ "tests/ui/test_ir_adapter.py",
44
+ "tests/ui/test_p1_widgets.py",
45
+ "tests/ui/fixtures/p1_widgets.ui",
46
+ "tests/ui/fixtures/p0_min.ui",
47
+ "tests/edm/test_converter_helpers.py",
48
+ "tests/edm/test_ir_adapter.py",
49
+ "tests/edm/test_parser_helpers.py",
50
+ "tests/edm/test_parser.py",
51
+ "tests/edm/test_converter.py",
52
+ "tests/edm/test_p1_widgets.py",
53
+ "tests/edm/test_visibility_rules.py",
54
+ "tests/edm/fixtures/p0_vis.edl",
55
+ "tests/edm/fixtures/p1_widgets.edl",
56
+ "tests/edm/fixtures/p0_min.edl",
57
+ "app/resources/file_minus.png",
58
+ "app/resources/folder_search.png",
59
+ "app/resources/play_circle_outline.png",
60
+ "app/resources/settings.png",
61
+ "app/resources/file_plus.png",
62
+ "app/resources/file_x.png",
63
+ "app/resources/folder_plus.png",
64
+ "app/src/view/output_select_dialog.py",
65
+ "app/src/view/main_window.ui",
66
+ "app/src/view/__init__.py",
67
+ "app/src/view/main_window.py",
68
+ "app/src/view/file_select_widget.py",
69
+ "app/src/view/options_window.py",
70
+ "app/src/model/__init__.py",
71
+ "app/src/model/app_model.py",
72
+ "app/src/model/options_model.py",
73
+ "pydmconverter/react.py",
74
+ "pydmconverter/widgets.py",
75
+ "pydmconverter/__init__.py",
76
+ "pydmconverter/exceptions.py",
77
+ "pydmconverter/launch_gui.sh",
78
+ "pydmconverter/widgets_helpers.py",
79
+ "pydmconverter/custom_types.py",
80
+ "pydmconverter/__main__.py",
81
+ "pydmconverter/ir/model.py",
82
+ "pydmconverter/ir/__init__.py",
83
+ "pydmconverter/ir/source.py",
84
+ "pydmconverter/ir/schema.py",
85
+ "pydmconverter/ir/fox.py",
86
+ "pydmconverter/ir/emit.py",
87
+ "pydmconverter/ir/transforms.py",
88
+ "pydmconverter/ir/ids.py",
89
+ "pydmconverter/ir/builder.py",
90
+ "pydmconverter/ir/macros.py",
91
+ "pydmconverter/ir/registry.py",
92
+ "pydmconverter/ir/base.py",
93
+ "pydmconverter/ir/data/screen-ir.schema.json",
94
+ "pydmconverter/ir/data/widget-registry/pv-byte-led.json",
95
+ "pydmconverter/ir/data/widget-registry/pv-label.json",
96
+ "pydmconverter/ir/data/widget-registry/pv-button.json",
97
+ "pydmconverter/ir/data/widget-registry/regular-button.json",
98
+ "pydmconverter/ir/data/widget-registry/pv-progress-bar.json",
99
+ "pydmconverter/ir/data/widget-registry/text-label.json",
100
+ "pydmconverter/ir/data/widget-registry/pv-slider.json",
101
+ "pydmconverter/ir/data/widget-registry/tabs.json",
102
+ "pydmconverter/ir/data/widget-registry/pv-checkbox.json",
103
+ "pydmconverter/ir/data/widget-registry/group-box.json",
104
+ "pydmconverter/ir/data/widget-registry/image-view.json",
105
+ "pydmconverter/ir/data/widget-registry/pv-enum-combobox.json",
106
+ "pydmconverter/ir/data/widget-registry/pv-text-input.json",
107
+ "pydmconverter/ir/data/widget-registry/.beaver-snapshot-sha",
108
+ "pydmconverter/ir/data/widget-registry/scroll-area.json",
109
+ "pydmconverter/ir/data/widget-registry/absolute-canvas.json",
110
+ "pydmconverter/ir/data/widget-registry/frame.json",
111
+ "pydmconverter/ir/data/widget-registry/embedded-display.json",
112
+ "pydmconverter/ir/data/widget-registry/related-display-button.json",
113
+ "pydmconverter/ir/data/widget-registry/pv-radio-group.json",
114
+ "pydmconverter/ir/data/widget-registry/pv-led.json",
115
+ "pydmconverter/ui/__init__.py",
116
+ "pydmconverter/ui/ir_adapter.py",
117
+ "pydmconverter/sites/__init__.py",
118
+ "pydmconverter/sites/slac.py",
119
+ "pydmconverter/edm/__init__.py",
120
+ "pydmconverter/edm/ir_adapter.py",
121
+ "pydmconverter/edm/converter_helpers.py",
122
+ "pydmconverter/edm/menumux.py",
123
+ "pydmconverter/edm/parser.py",
124
+ "pydmconverter/edm/converter.py",
125
+ "pydmconverter/edm/edm_qt.py",
126
+ "pydmconverter/edm/parser_helpers.py",
127
+ "examples/prosilica.edl",
128
+ "examples/TEM_mapping.edl",
129
+ "examples/all_bsy0_main.edl",
130
+ "examples/all_bsy0_main_with_groups.edl",
131
+ ".github/ISSUE_TEMPLATE/feature-request.yml",
132
+ ".github/ISSUE_TEMPLATE/bug-report.yml",
133
+ ".github/workflows/pypi_release.yml",
134
+ ".github/workflows/tests.yml",
135
+ ".github/workflows/lint.yml",
136
+ ".github/workflows/gh-pages.yml"
137
+ ]
138
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "1.0.4",
3
+ "distance": 0,
4
+ "node": "gd722ac6fca7f9362464771f968e5b6c8d56d1d4e",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-06-25"
8
+ }
@@ -13,6 +13,7 @@ class OptionsModel:
13
13
  def __init__(self):
14
14
  # General options
15
15
  self.output_folder = None
16
+ self.override_existing = False
16
17
 
17
18
  # EDM options
18
19
  self.edm_override_def_colors = False
@@ -39,6 +40,9 @@ class OptionsModel:
39
40
  output_folder = data.get("output_folder", None)
40
41
  if output_folder is not None and os.path.exists(output_folder):
41
42
  self.output_folder = output_folder
43
+ override_existing = data.get("override_existing", None)
44
+ if override_existing is not None:
45
+ self.override_existing = override_existing
42
46
 
43
47
  # EDM options
44
48
  edm_override_def_colors = data.get("edm_override_def_colors", None)
@@ -61,6 +65,8 @@ class OptionsModel:
61
65
  # General options
62
66
  if self.output_folder is not None:
63
67
  data["output_folder"] = self.output_folder
68
+ if self.override_existing is not False:
69
+ data["override_existing"] = self.override_existing
64
70
 
65
71
  # EDM options
66
72
  if self.edm_override_def_colors is not False:
@@ -10,6 +10,7 @@ from time import sleep
10
10
  from typing import List
11
11
  from pydm import Display
12
12
  from qtpy.QtCore import Slot, QCoreApplication
13
+ from qtpy.QtGui import QBrush, QColor
13
14
  from qtpy.QtWidgets import (
14
15
  QFileDialog,
15
16
  QTableWidget,
@@ -27,6 +28,9 @@ import logging
27
28
  logging.basicConfig(level=logging.INFO)
28
29
  logger = logging.getLogger(__name__)
29
30
 
31
+ CONVERTED_ROW_COLOR = QColor(200, 230, 201)
32
+ FAILED_ROW_COLOR = QColor(255, 205, 210)
33
+
30
34
 
31
35
  class MainWindow(Display):
32
36
  def __init__(self, parent=None, args=None, macros=None, ui_filename=None):
@@ -174,6 +178,17 @@ class MainWindow(Display):
174
178
  if conversion_status == "Converted":
175
179
  table_widget.removeRow(i)
176
180
 
181
+ def set_row_status(self, row: int, status: str, color: QColor, tooltip: str = "") -> None:
182
+ """Sets the status cell of a row and colors the whole row"""
183
+ table_widget: QTableWidget = self.ui.table_widget
184
+ status_item = QTableWidgetItem(status)
185
+ status_item.setToolTip(tooltip)
186
+ table_widget.setItem(row, 2, status_item)
187
+ for col in range(table_widget.columnCount()):
188
+ item = table_widget.item(row, col)
189
+ if item is not None:
190
+ item.setBackground(QBrush(color))
191
+
177
192
  @Slot()
178
193
  def on_convert_button_clicked(self) -> None:
179
194
  table_widget: QTableWidget = self.ui.table_widget
@@ -182,12 +197,14 @@ class MainWindow(Display):
182
197
  output_file = table_widget.item(row, 1).text()
183
198
  file_type = os.path.splitext(input_file)[1].lower()
184
199
  try:
185
- pydmconverter.__main__.run(input_file, output_file, file_type, override=True)
200
+ pydmconverter.__main__.run(
201
+ input_file, output_file, file_type, override=self.options_model.override_existing
202
+ )
186
203
  logger.debug(f"converted {input_file} to {output_file}")
187
- table_widget.setItem(row, 2, QTableWidgetItem("Converted"))
204
+ self.set_row_status(row, "Converted", CONVERTED_ROW_COLOR)
188
205
  except Exception as msg:
189
206
  logger.debug(msg)
190
- table_widget.setItem(row, 2, QTableWidgetItem("Failed"))
207
+ self.set_row_status(row, "Failed", FAILED_ROW_COLOR, tooltip=str(msg))
191
208
  QCoreApplication.processEvents()
192
209
 
193
210
  """parser = self.app_model.parsers[file_type](input_file)
@@ -47,12 +47,20 @@ class OptionsWindow(QWidget):
47
47
  self.output_folder_select = FileSelectWidget(path=self.options_model.output_folder, select_dir=False)
48
48
  output_folder_group_layout.addWidget(self.output_folder_select)
49
49
 
50
+ conversion_group = QGroupBox("Conversion")
51
+ conversion_group_layout = QVBoxLayout()
52
+ conversion_group.setLayout(conversion_group_layout)
53
+ self.override_existing_checkbox = QCheckBox("Overwrite existing output files")
54
+ self.override_existing_checkbox.setChecked(self.options_model.override_existing)
55
+ conversion_group_layout.addWidget(self.override_existing_checkbox)
56
+
50
57
  self.general_group_view = QWidget()
51
58
  general_group_layout = QVBoxLayout()
52
59
  self.general_group_view.setLayout(general_group_layout)
53
60
  general_group_label = QLabel("General")
54
61
  general_group_layout.addWidget(general_group_label)
55
62
  general_group_layout.addWidget(output_folder_group)
63
+ general_group_layout.addWidget(conversion_group)
56
64
  general_group_layout.addStretch()
57
65
 
58
66
  edm_colors_group = QGroupBox("colors.list")
@@ -122,6 +130,7 @@ class OptionsWindow(QWidget):
122
130
  else:
123
131
  QMessageBox.critical(self, "Invalid Path", "The entered output folder path is not valid.")
124
132
  return False
133
+ self.options_model.override_existing = self.override_existing_checkbox.isChecked()
125
134
 
126
135
  # EDM options
127
136
  colors_path = self.edm_override_file_select.get_path()
@@ -29,7 +29,21 @@ def run_gui() -> None:
29
29
  subprocess.run(["bash", str(launch_script)], check=True)
30
30
 
31
31
 
32
- def run(input_file, output_file, input_file_type=".edl", override=False, scrollable=False, site=None):
32
+ def run(
33
+ input_file,
34
+ output_file,
35
+ input_file_type=".edl",
36
+ override=False,
37
+ scrollable=False,
38
+ site=None,
39
+ calc_list=None,
40
+ target="pydm",
41
+ out_format="json",
42
+ ):
43
+ if target == "react":
44
+ run_react(input_file, output_file, override)
45
+ return
46
+
33
47
  input_path: Path = Path(input_file)
34
48
  output_path: Path = Path(output_file)
35
49
 
@@ -39,7 +53,7 @@ def run(input_file, output_file, input_file_type=".edl", override=False, scrolla
39
53
  if output_path.is_file() and not override:
40
54
  raise FileExistsError(f"Output file '{output_path}' already exists. Use --override or -o to overwrite it.")
41
55
  copy_img_files(input_path.parent, output_path.parent)
42
- convert(str(input_path), str(output_path), scrollable, site=site)
56
+ convert(str(input_path), str(output_path), scrollable, site=site, calc_list_file=calc_list)
43
57
  else:
44
58
  if input_file_type[0] != ".": # prepending . so it will not pick up other file types with same suffix
45
59
  input_file_type = "." + input_file_type
@@ -47,7 +61,7 @@ def run(input_file, output_file, input_file_type=".edl", override=False, scrolla
47
61
  files_found: int
48
62
  files_failed: list[str]
49
63
  files_found, files_failed = convert_files_in_folder(
50
- input_path, output_path, input_file_type, override, scrollable, site=site
64
+ input_path, output_path, input_file_type, override, scrollable, site=site, calc_list=calc_list
51
65
  )
52
66
 
53
67
  if files_found == 0:
@@ -61,6 +75,26 @@ def run(input_file, output_file, input_file_type=".edl", override=False, scrolla
61
75
  print(f"Failed files: {', '.join(map(lambda path: str(path), files_failed))}")
62
76
 
63
77
 
78
+ def run_react(input_file, output_file, override) -> None:
79
+ """Convert .edl/.ui to Canopy Screen IR JSON (the --target react path)."""
80
+ from pydmconverter import react
81
+
82
+ input_path = Path(input_file)
83
+ output_path = Path(output_file)
84
+ if input_path.is_file():
85
+ out = react.convert_file(input_path, output_path, override=override)
86
+ print(f"Converted {input_path} -> {out}")
87
+ else:
88
+ output_path.mkdir(parents=True, exist_ok=True)
89
+ found, failed = react.convert_folder(input_path, output_path, override=override)
90
+ if found == 0:
91
+ print(f"No {' or '.join(react.SUPPORTED_SUFFIXES)} files found in {input_path}")
92
+ else:
93
+ print(f"{found - len(failed)} files converted from {input_path}")
94
+ if failed:
95
+ print(f"{len(failed)} files failed to convert. Use --override or -o to overwrite existing files.")
96
+
97
+
64
98
  def run_cli(args: argparse.Namespace) -> None:
65
99
  """
66
100
  run PyDMConverter through command line
@@ -77,7 +111,18 @@ def run_cli(args: argparse.Namespace) -> None:
77
111
  override: bool = args.override
78
112
  scrollable: bool = args.scrollable
79
113
  site: str = args.site
80
- run(input_file, output_file, input_file_type, override, scrollable, site=site)
114
+ calc_list: str = args.calc_list
115
+ run(
116
+ input_file,
117
+ output_file,
118
+ input_file_type,
119
+ override,
120
+ scrollable,
121
+ site=site,
122
+ calc_list=calc_list,
123
+ target=args.target,
124
+ out_format=args.format,
125
+ )
81
126
 
82
127
 
83
128
  """
@@ -126,7 +171,13 @@ def copy_img_files(input_path: Path, output_path: Path) -> None:
126
171
 
127
172
 
128
173
  def convert_files_in_folder(
129
- input_path: Path, output_path: Path, input_file_type: str, override: bool, scrollable: bool, site=None
174
+ input_path: Path,
175
+ output_path: Path,
176
+ input_file_type: str,
177
+ override: bool,
178
+ scrollable: bool,
179
+ site=None,
180
+ calc_list=None,
130
181
  ) -> tuple[int, list[str]]:
131
182
  """Recursively runs convert on files in directory and subdirectories
132
183
 
@@ -162,7 +213,7 @@ def convert_files_in_folder(
162
213
  logging.warning(f"Skipped: {output_file_path} already exists. Use --override or -o to overwrite it.")
163
214
  else:
164
215
  try:
165
- convert(file, output_file_path, scrollable, site=site)
216
+ convert(file, output_file_path, scrollable, site=site, calc_list_file=calc_list)
166
217
  except Exception as e:
167
218
  files_failed.append(str(file))
168
219
  logging.warning(f"Failed to convert {file}: {e}")
@@ -171,7 +222,7 @@ def convert_files_in_folder(
171
222
  subdirectories = [item for item in input_path.iterdir() if item.is_dir()]
172
223
  for subdir in subdirectories:
173
224
  sub_found, sub_failed = convert_files_in_folder(
174
- subdir, output_path / subdir.name, input_file_type, override, scrollable, site=site
225
+ subdir, output_path / subdir.name, input_file_type, override, scrollable, site=site, calc_list=calc_list
175
226
  )
176
227
  files_found += sub_found
177
228
  files_failed += sub_failed
@@ -233,6 +284,24 @@ def main() -> None:
233
284
  default=None,
234
285
  help="Apply site-specific conversion rules (e.g., slac)",
235
286
  )
287
+ parser.add_argument(
288
+ "--calc-list",
289
+ type=str,
290
+ default=None,
291
+ help="Path to an EDM calc.list file used to resolve named CALC PVs",
292
+ )
293
+ parser.add_argument(
294
+ "--target",
295
+ choices=["pydm", "react"],
296
+ default="pydm",
297
+ help="Output target: 'pydm' writes .ui (default), 'react' writes Canopy Screen IR .screen.json",
298
+ )
299
+ parser.add_argument(
300
+ "--format",
301
+ choices=["json"],
302
+ default="json",
303
+ help="Output format for --target react (json; TSX is generated by the Screen Builder)",
304
+ )
236
305
  args: argparse.Namespace = parser.parse_args()
237
306
 
238
307
  if args.input_file:
@@ -1,4 +1,5 @@
1
1
  from dataclasses import dataclass
2
+ from typing import Optional, Union
2
3
 
3
4
 
4
5
  @dataclass(frozen=True)
@@ -24,8 +25,8 @@ class RuleArguments:
24
25
  channel: str
25
26
  show_on_true: bool
26
27
  initial_value: bool
27
- visMin: int
28
- visMax: int
28
+ visMin: Optional[Union[int, float, str]]
29
+ visMax: Optional[Union[int, float, str]]
29
30
 
30
31
  def __iter__(self):
31
32
  yield self.rule_type
@@ -47,12 +47,13 @@ CUSTOM_WIDGET_DEFINITIONS = {
47
47
  "PyDMShellCommand": {"extends": "QPushButton", "header": "pydm.widgets.shell_command", "container": ""},
48
48
  "PyDMSlider": {"extends": "QWidget", "header": "pydm.widgets.slider", "container": ""},
49
49
  "PyDMWaveformTable": {"extends": "QTableWidget", "header": "pydm.widgets.waveformtable", "container": ""},
50
+ "PyDMAnalogIndicator": {"extends": "QWidget", "header": "pydm.widgets.analog_indicator", "container": ""},
50
51
  }
51
52
 
52
53
 
53
- def convert(input_path, output_path, scrollable=False, site=None):
54
+ def convert(input_path, output_path, scrollable=False, site=None, calc_list_file=None):
54
55
  try:
55
- edm_parser = EDMFileParser(input_path, output_path)
56
+ edm_parser = EDMFileParser(input_path, output_path, calc_list_file=calc_list_file)
56
57
  logger.info(f"Successfully parsed EDM file: {input_path}")
57
58
  except FileNotFoundError:
58
59
  logger.error("File Not Found")