pychemstation 0.10.5__tar.gz → 0.10.6__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 (240) hide show
  1. {pychemstation-0.10.5 → pychemstation-0.10.6}/.gitignore +1 -1
  2. {pychemstation-0.10.5 → pychemstation-0.10.6}/PKG-INFO +1 -1
  3. pychemstation-0.10.6/pychemstation/analysis/__init__.py +11 -0
  4. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/control/controllers/__init__.py +2 -2
  5. pychemstation-0.10.6/pychemstation/control/controllers/abc_tables/device.py +15 -0
  6. pychemstation-0.10.5/pychemstation/control/controllers/tables/table.py → pychemstation-0.10.6/pychemstation/control/controllers/abc_tables/run.py +24 -195
  7. pychemstation-0.10.6/pychemstation/control/controllers/abc_tables/table.py +221 -0
  8. pychemstation-0.10.6/pychemstation/control/controllers/comm.py +150 -0
  9. {pychemstation-0.10.5/pychemstation/control/controllers/tables → pychemstation-0.10.6/pychemstation/control/controllers/data_aq}/method.py +2 -2
  10. {pychemstation-0.10.5/pychemstation/control/controllers/tables → pychemstation-0.10.6/pychemstation/control/controllers/data_aq}/sequence.py +72 -53
  11. pychemstation-0.10.6/pychemstation/control/controllers/devices/__init__.py +3 -0
  12. pychemstation-0.10.6/pychemstation/control/controllers/devices/injector.py +106 -0
  13. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/control/hplc.py +5 -1
  14. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/utils/injector_types.py +22 -2
  15. pychemstation-0.10.5/pychemstation/control/controllers/comm.py → pychemstation-0.10.6/pychemstation/utils/mocking/abc_comm.py +18 -104
  16. pychemstation-0.10.6/pychemstation/utils/mocking/mock_comm.py +5 -0
  17. pychemstation-0.10.6/pychemstation/utils/mocking/mock_hplc.py +2 -0
  18. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/utils/sequence_types.py +19 -0
  19. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/utils/table_types.py +6 -0
  20. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/utils/tray_types.py +36 -1
  21. {pychemstation-0.10.5 → pychemstation-0.10.6}/pyproject.toml +1 -1
  22. pychemstation-0.10.6/tests/__init__.py +0 -0
  23. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/out.txt +3986 -0
  24. pychemstation-0.10.6/tests/test_injector.py +39 -0
  25. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/test_integration.py +7 -7
  26. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/test_method.py +75 -11
  27. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/test_offline.py +3 -4
  28. pychemstation-0.10.6/tests/test_online.py +79 -0
  29. pychemstation-0.10.6/tests/test_sequence.py +217 -0
  30. {pychemstation-0.10.5 → pychemstation-0.10.6}/uv.lock +1 -1
  31. pychemstation-0.10.5/pychemstation/analysis/__init__.py +0 -4
  32. pychemstation-0.10.5/pychemstation/control/controllers/devices/device.py +0 -74
  33. pychemstation-0.10.5/pychemstation/control/controllers/devices/injector.py +0 -73
  34. pychemstation-0.10.5/tests/test_online.py +0 -303
  35. pychemstation-0.10.5/tests/test_sequence.py +0 -91
  36. {pychemstation-0.10.5 → pychemstation-0.10.6}/.gitlab-ci.yml +0 -0
  37. {pychemstation-0.10.5 → pychemstation-0.10.6}/.pre-commit-config.yaml +0 -0
  38. {pychemstation-0.10.5 → pychemstation-0.10.6}/CHANGELOG.md +0 -0
  39. {pychemstation-0.10.5 → pychemstation-0.10.6}/CONTRIBUTING.md +0 -0
  40. {pychemstation-0.10.5 → pychemstation-0.10.6}/LICENSE +0 -0
  41. {pychemstation-0.10.5 → pychemstation-0.10.6}/README.md +0 -0
  42. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/index.html +0 -0
  43. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/pychemstation/analysis/base_spectrum.html +0 -0
  44. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/pychemstation/analysis/spec_utils.html +0 -0
  45. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/pychemstation/analysis/utils.html +0 -0
  46. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/pychemstation/analysis.html +0 -0
  47. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/pychemstation/control/chromatogram.html +0 -0
  48. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/pychemstation/control/hplc.html +0 -0
  49. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/pychemstation/control.html +0 -0
  50. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/pychemstation/generated.html +0 -0
  51. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/pychemstation/utils/chemstation.html +0 -0
  52. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/pychemstation/utils/constants.html +0 -0
  53. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/pychemstation/utils/hplc_param_types.html +0 -0
  54. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/pychemstation/utils.html +0 -0
  55. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/pychemstation.html +0 -0
  56. {pychemstation-0.10.5 → pychemstation-0.10.6}/doc/search.js +0 -0
  57. {pychemstation-0.10.5 → pychemstation-0.10.6}/out.txt +0 -0
  58. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/__init__.py +0 -0
  59. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/analysis/base_spectrum.py +0 -0
  60. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/analysis/chromatogram.py +0 -0
  61. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/analysis/process_report.py +0 -0
  62. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/control/README.md +0 -0
  63. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/control/__init__.py +0 -0
  64. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/control/controllers/README.md +0 -0
  65. {pychemstation-0.10.5/pychemstation/control/controllers/devices → pychemstation-0.10.6/pychemstation/control/controllers/abc_tables}/__init__.py +0 -0
  66. {pychemstation-0.10.5/pychemstation/control/controllers/tables → pychemstation-0.10.6/pychemstation/control/controllers/data_aq}/__init__.py +0 -0
  67. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/generated/__init__.py +0 -0
  68. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/generated/dad_method.py +0 -0
  69. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/generated/pump_method.py +0 -0
  70. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/utils/__init__.py +0 -0
  71. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/utils/macro.py +0 -0
  72. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/utils/method_types.py +0 -0
  73. {pychemstation-0.10.5/tests → pychemstation-0.10.6/pychemstation/utils/mocking}/__init__.py +0 -0
  74. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/utils/num_utils.py +0 -0
  75. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/utils/parsing.py +0 -0
  76. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/utils/pump_types.py +0 -0
  77. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation/utils/spec_utils.py +0 -0
  78. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation.egg-info/PKG-INFO +0 -0
  79. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation.egg-info/SOURCES.txt +0 -0
  80. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation.egg-info/dependency_links.txt +0 -0
  81. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation.egg-info/requires.txt +0 -0
  82. {pychemstation-0.10.5 → pychemstation-0.10.6}/pychemstation.egg-info/top_level.txt +0 -0
  83. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/0_2025-03-15 19-14-35.PDF +0 -0
  84. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/ACQRES.REG +0 -0
  85. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/CSlbk.ini +0 -0
  86. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DA.M/DAMETHOD.REG +0 -0
  87. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DA.M/INFO.MTH +0 -0
  88. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DA.M/RECALIB.MTH +0 -0
  89. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DA.M/rpthead.txt +0 -0
  90. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DAD1.UV +0 -0
  91. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DAD1A.ch +0 -0
  92. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DAD1A.npz +0 -0
  93. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DAD1B.ch +0 -0
  94. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DAD1B.npz +0 -0
  95. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DAD1C.ch +0 -0
  96. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DAD1C.npz +0 -0
  97. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DAD1D.ch +0 -0
  98. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DAD1D.npz +0 -0
  99. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DAD1E.ch +0 -0
  100. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DAD1E.npz +0 -0
  101. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/DiagResults.REG +0 -0
  102. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/PMP1.AnalyticalResults.drvml +0 -0
  103. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/REPORT01.CSV +0 -0
  104. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/REPORT02.CSV +0 -0
  105. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/REPORT03.CSV +0 -0
  106. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/REPORT04.CSV +0 -0
  107. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/REPORT05.CSV +0 -0
  108. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/RUN.LOG +0 -0
  109. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/Report.TXT +0 -0
  110. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/Report00.CSV +0 -0
  111. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/Report01.xls +0 -0
  112. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/SAMPLE.XML +0 -0
  113. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/SAMPLE.XML.bak +0 -0
  114. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/WLS1.Sampler.scml +0 -0
  115. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/acq.macaml +0 -0
  116. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/acq.txt +0 -0
  117. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/acq_MethHist.txt +0 -0
  118. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/acq_damethod.reg +0 -0
  119. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/da.macaml +0 -0
  120. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/lcdiag.reg +0 -0
  121. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/sample.acaml +0 -0
  122. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/0_2025-03-15 19-14-35.D/single.B +0 -0
  123. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/ACQRES.REG +0 -0
  124. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/AUTOMATICALLY_GENERATED_REPORT01.CSV +0 -0
  125. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/AUTOMATICALLY_GENERATED_REPORT02.CSV +0 -0
  126. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/AUTOMATICALLY_GENERATED_REPORT03.CSV +0 -0
  127. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/AUTOMATICALLY_GENERATED_REPORT04.CSV +0 -0
  128. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/AUTOMATICALLY_GENERATED_REPORT05.CSV +0 -0
  129. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/Automatically_Generated_Report.TXT +0 -0
  130. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/Automatically_Generated_Report00.CSV +0 -0
  131. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/CSlbk.ini +0 -0
  132. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DA.M/DAMETHOD.REG +0 -0
  133. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DA.M/INFO.MTH +0 -0
  134. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DA.M/RECALIB.MTH +0 -0
  135. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DA.M/rpthead.txt +0 -0
  136. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1.UV +0 -0
  137. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1A.ch +0 -0
  138. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1A.npz +0 -0
  139. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1B.ch +0 -0
  140. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1B.npz +0 -0
  141. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1C.ch +0 -0
  142. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1C.npz +0 -0
  143. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1D.ch +0 -0
  144. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1D.npz +0 -0
  145. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1E.ch +0 -0
  146. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1E.npz +0 -0
  147. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1F.ch +0 -0
  148. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1F.npz +0 -0
  149. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1G.ch +0 -0
  150. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1G.npz +0 -0
  151. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1H.ch +0 -0
  152. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DAD1H.npz +0 -0
  153. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/DiagResults.REG +0 -0
  154. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/Limsinf.xml +0 -0
  155. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/PMP1.AnalyticalResults.drvml +0 -0
  156. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/RUN.LOG +0 -0
  157. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/SAMPLE.XML +0 -0
  158. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/SAMPLE.XML.bak +0 -0
  159. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/WLS1.Sampler.scml +0 -0
  160. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/acq.macaml +0 -0
  161. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/acq.txt +0 -0
  162. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/acq_MethHist.txt +0 -0
  163. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/acq_damethod.reg +0 -0
  164. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/da.macaml +0 -0
  165. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/lcdiag.reg +0 -0
  166. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/sample.acaml +0 -0
  167. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/10 IS 2025-02-10 23-41-33_10_2025-02-11 02-21-44.D/single.B +0 -0
  168. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/constants.py +0 -0
  169. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_talk.mac +0 -0
  170. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/CSlbk.ini +0 -0
  171. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/ACQ.MS +0 -0
  172. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/Agilent1200erDadDriver1.RapidControl.ConfigXML.xml +0 -0
  173. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/Agilent1200erDadDriver1.RapidControl.MethodMetaData.xml +0 -0
  174. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/Agilent1200erDadDriver1.RapidControl.MethodXML.xml +0 -0
  175. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/AgilentColumnCompDriver1.RapidControl.ConfigXML.xml +0 -0
  176. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/AgilentColumnCompDriver1.RapidControl.MethodMetaData.xml +0 -0
  177. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/AgilentColumnCompDriver1.RapidControl.MethodXML.xml +0 -0
  178. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/AgilentPumpDriver1.RapidControl.ConfigXML.xml +0 -0
  179. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/AgilentPumpDriver1.RapidControl.MethodMetaData.xml +0 -0
  180. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/AgilentPumpDriver1.RapidControl.MethodXML.xml +0 -0
  181. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/AgilentSamplerDriver1.RapidControl.ConfigXML.xml +0 -0
  182. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/AgilentSamplerDriver1.RapidControl.MethodMetaData.xml +0 -0
  183. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/AgilentSamplerDriver1.RapidControl.MethodXML.xml +0 -0
  184. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/AgilentSamplerDriver1.RapidControl.PretreatXML.xml +0 -0
  185. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/DAMETHOD.REG +0 -0
  186. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/FIA.REG +0 -0
  187. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/INFO.MTH +0 -0
  188. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/INJECTOR.MTH +0 -0
  189. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/MassHunterIntegration.ini +0 -0
  190. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/RECALIB.MTH +0 -0
  191. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/RapidControl.InstrumentConfig.xml +0 -0
  192. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/rpthead.txt +0 -0
  193. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/GENERAL-POROSHELL-OPT.M/smpl_pur.mth +0 -0
  194. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/Methods.Reg +0 -0
  195. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/hplc_testing.B +0 -0
  196. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/hplc_testing.LOG +0 -0
  197. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/hplc_testing.S +0 -0
  198. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/hplc_testing.Start +0 -0
  199. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/ACQRES.REG +0 -0
  200. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/CSlbk.ini +0 -0
  201. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DA.M/DAMETHOD.REG +0 -0
  202. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DA.M/INFO.MTH +0 -0
  203. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DA.M/RECALIB.MTH +0 -0
  204. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DA.M/rpthead.txt +0 -0
  205. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DAD1.UV +0 -0
  206. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DAD1A.ch +0 -0
  207. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DAD1A.npz +0 -0
  208. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DAD1B.ch +0 -0
  209. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DAD1B.npz +0 -0
  210. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DAD1C.ch +0 -0
  211. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DAD1C.npz +0 -0
  212. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DAD1D.ch +0 -0
  213. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DAD1D.npz +0 -0
  214. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DAD1E.ch +0 -0
  215. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DAD1E.npz +0 -0
  216. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/DiagResults.REG +0 -0
  217. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/Limsinf.xml +0 -0
  218. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/PMP1.AnalyticalResults.drvml +0 -0
  219. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/REPORT01.CSV +0 -0
  220. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/REPORT02.CSV +0 -0
  221. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/REPORT03.CSV +0 -0
  222. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/REPORT04.CSV +0 -0
  223. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/REPORT05.CSV +0 -0
  224. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/RUN.LOG +0 -0
  225. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/Report.TXT +0 -0
  226. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/Report00.CSV +0 -0
  227. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/Report01.xls +0 -0
  228. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/SAMPLE.XML +0 -0
  229. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/SAMPLE.XML.bak +0 -0
  230. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/WLS1.Sampler.scml +0 -0
  231. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/acq.macaml +0 -0
  232. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/acq.txt +0 -0
  233. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/acq_MethHist.txt +0 -0
  234. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/acq_damethod.reg +0 -0
  235. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/da.macaml +0 -0
  236. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/hplc_testing 2025-03-27 17-13-47_run seq with new method.PDF +0 -0
  237. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/lcdiag.reg +0 -0
  238. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/run seq with new method.D/sequence.acam_ +0 -0
  239. {pychemstation-0.10.5 → pychemstation-0.10.6}/tests/hplc_testing 2025-03-27 17-13-47/sequence.acaml +0 -0
  240. {pychemstation-0.10.5 → pychemstation-0.10.6}/update-lib.sh +0 -0
@@ -6,4 +6,4 @@
6
6
  target
7
7
  .DS_Store
8
8
  env
9
- venv
9
+ venv
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pychemstation
3
- Version: 0.10.5
3
+ Version: 0.10.6
4
4
  Summary: Library to interact with Chemstation software, primarily used in Hein lab
5
5
  Project-URL: Documentation, https://pychemstation-e5a086.gitlab.io/pychemstation.html
6
6
  Project-URL: Repository, https://gitlab.com/heingroup/device-api/pychemstation
@@ -0,0 +1,11 @@
1
+ from .process_report import CSVProcessor
2
+ from .process_report import TXTProcessor
3
+ from .chromatogram import AgilentChannelChromatogramData
4
+ from .chromatogram import AgilentHPLCChromatogram
5
+
6
+ __all__ = [
7
+ "CSVProcessor",
8
+ "TXTProcessor",
9
+ "AgilentChannelChromatogramData",
10
+ "AgilentHPLCChromatogram",
11
+ ]
@@ -3,6 +3,6 @@
3
3
  """
4
4
 
5
5
  from .comm import CommunicationController
6
- from . import tables
6
+ from . import data_aq
7
7
 
8
- __all__ = ["CommunicationController", "tables"]
8
+ __all__ = ["CommunicationController", "data_aq"]
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import ABC
4
+
5
+ from ....control.controllers import CommunicationController
6
+ from ....utils.table_types import Table
7
+ from .table import ABCTableController
8
+
9
+
10
+ class DeviceController(ABCTableController, ABC):
11
+ def __init__(
12
+ self, controller: CommunicationController, table: Table, offline: bool
13
+ ):
14
+ super().__init__(controller=controller, table=table)
15
+ self.offline = offline
@@ -17,6 +17,7 @@ import polling
17
17
  import rainbow as rb
18
18
  from result import Err, Result, Ok
19
19
 
20
+ from .table import ABCTableController
20
21
  from ....analysis.process_report import (
21
22
  AgilentReport,
22
23
  CSVProcessor,
@@ -28,15 +29,15 @@ from pychemstation.analysis.chromatogram import (
28
29
  AgilentChannelChromatogramData,
29
30
  AgilentHPLCChromatogram,
30
31
  )
31
- from ....utils.macro import Command, HPLCRunningStatus, Response
32
+ from ....utils.macro import HPLCRunningStatus
32
33
  from ....utils.method_types import MethodDetails
33
34
  from ....utils.sequence_types import SequenceTable
34
- from ....utils.table_types import RegisterFlag, Table, TableOperation, T
35
+ from ....utils.table_types import Table, T
35
36
 
36
37
  TableType = Union[MethodDetails, SequenceTable]
37
38
 
38
39
 
39
- class TableController(abc.ABC):
40
+ class RunController(ABCTableController, abc.ABC):
40
41
  def __init__(
41
42
  self,
42
43
  controller: Optional[CommunicationController],
@@ -45,8 +46,10 @@ class TableController(abc.ABC):
45
46
  table: Table,
46
47
  offline: bool = False,
47
48
  ):
48
- self.controller = controller
49
- self.table_locator = table
49
+ super().__init__(controller=controller, table=table)
50
+ warnings.warn(
51
+ "This abstract class is not meant to be initialized. Use MethodController or SequenceController."
52
+ )
50
53
  self.table_state: Optional[TableType] = None
51
54
  self.curr_run_starting_time: Optional[float] = None
52
55
  self.timeout: Optional[float] = None
@@ -76,179 +79,27 @@ class TableController(abc.ABC):
76
79
  self.uv: Dict[int, AgilentHPLCChromatogram] = {}
77
80
  self.data_files: List = []
78
81
 
79
- def receive(self) -> Result[Response, str]:
80
- if self.controller:
81
- for _ in range(10):
82
- try:
83
- return self.controller.receive()
84
- except IndexError:
85
- continue
86
- return Err("Could not parse response")
87
- else:
88
- raise ValueError("Controller is offline!")
89
-
90
- def send(self, cmd: Union[Command, str]):
91
- if not self.controller:
92
- raise RuntimeError(
93
- "Communication controller must be initialized before sending command. It is currently in offline mode."
94
- )
95
- self.controller.send(cmd)
96
-
97
- def sleepy_send(self, cmd: Union[Command, str]):
98
- if self.controller:
99
- self.controller.sleepy_send(cmd)
100
- else:
101
- raise ValueError("Controller is offline")
102
-
103
- def sleep(self, seconds: int):
104
- """
105
- Tells the HPLC to wait for a specified number of seconds.
106
-
107
- :param seconds: number of seconds to wait
108
- """
109
- self.send(Command.SLEEP_CMD.value.format(seconds=seconds))
110
-
111
- def get_num(self, row: int, col_name: RegisterFlag) -> Union[int, float]:
112
- if self.controller:
113
- return self.controller.get_num_val(
114
- TableOperation.GET_ROW_VAL.value.format(
115
- register=self.table_locator.register,
116
- table_name=self.table_locator.name,
117
- row=row,
118
- col_name=col_name.value,
119
- )
120
- )
121
- else:
122
- raise ValueError("Controller is offline")
123
-
124
- def get_text(self, row: int, col_name: RegisterFlag) -> str:
125
- if self.controller:
126
- return self.controller.get_text_val(
127
- TableOperation.GET_ROW_TEXT.value.format(
128
- register=self.table_locator.register,
129
- table_name=self.table_locator.name,
130
- row=row,
131
- col_name=col_name.value,
132
- )
133
- )
134
- else:
135
- raise ValueError("Controller is offline")
136
-
137
- def add_new_col_num(self, col_name: RegisterFlag, val: Union[int, float]):
138
- self.sleepy_send(
139
- TableOperation.NEW_COL_VAL.value.format(
140
- register=self.table_locator.register,
141
- table_name=self.table_locator.name,
142
- col_name=col_name,
143
- val=val,
144
- )
145
- )
146
-
147
- def add_new_col_text(self, col_name: RegisterFlag, val: str):
148
- self.sleepy_send(
149
- TableOperation.NEW_COL_TEXT.value.format(
150
- register=self.table_locator.register,
151
- table_name=self.table_locator.name,
152
- col_name=col_name,
153
- val=val,
154
- )
155
- )
156
-
157
- def _edit_row_num(
158
- self, col_name: RegisterFlag, val: Union[int, float], row: Optional[int] = None
159
- ):
160
- self.sleepy_send(
161
- TableOperation.EDIT_ROW_VAL.value.format(
162
- register=self.table_locator.register,
163
- table_name=self.table_locator.name,
164
- row=row if row is not None else "Rows",
165
- col_name=col_name,
166
- val=val,
167
- )
168
- )
169
-
170
- def _edit_row_text(
171
- self, col_name: RegisterFlag, val: str, row: Optional[int] = None
172
- ):
173
- self.sleepy_send(
174
- TableOperation.EDIT_ROW_TEXT.value.format(
175
- register=self.table_locator.register,
176
- table_name=self.table_locator.name,
177
- row=row if row is not None else "Rows",
178
- col_name=col_name,
179
- val=val,
180
- )
181
- )
182
-
183
82
  @abc.abstractmethod
184
- def get_row(self, row: int):
83
+ def fuzzy_match_most_recent_folder(self, most_recent_folder: T) -> Result[T, str]:
185
84
  pass
186
85
 
187
- def delete_row(self, row: int):
188
- self.sleepy_send(
189
- TableOperation.DELETE_ROW.value.format(
190
- register=self.table_locator.register,
191
- table_name=self.table_locator.name,
192
- row=row,
193
- )
194
- )
195
-
196
- def add_row(self):
197
- """
198
- Adds a row to the provided table for currently loaded method or sequence.
199
- """
200
- self.sleepy_send(
201
- TableOperation.NEW_ROW.value.format(
202
- register=self.table_locator.register, table_name=self.table_locator.name
203
- )
204
- )
205
-
206
- def delete_table(self):
207
- """
208
- Deletes the table for the current loaded method or sequence.
209
- """
210
- self.sleepy_send(
211
- TableOperation.DELETE_TABLE.value.format(
212
- register=self.table_locator.register, table_name=self.table_locator.name
213
- )
214
- )
215
-
216
- def new_table(self):
217
- """
218
- Creates the table for the currently loaded method or sequence.
219
- """
220
- self.send(
221
- TableOperation.CREATE_TABLE.value.format(
222
- register=self.table_locator.register, table_name=self.table_locator.name
223
- )
224
- )
86
+ @abc.abstractmethod
87
+ def get_data(
88
+ self, custom_path: Optional[str] = None
89
+ ) -> Union[List[AgilentChannelChromatogramData], AgilentChannelChromatogramData]:
90
+ pass
225
91
 
226
- def get_num_rows(self) -> Result[Response, str]:
227
- self.send(
228
- TableOperation.GET_NUM_ROWS.value.format(
229
- register=self.table_locator.register,
230
- table_name=self.table_locator.name,
231
- col_name=RegisterFlag.NUM_ROWS,
232
- )
233
- )
234
- self.send(
235
- Command.GET_ROWS_CMD.value.format(
236
- register=self.table_locator.register,
237
- table_name=self.table_locator.name,
238
- col_name=RegisterFlag.NUM_ROWS,
239
- )
240
- )
241
- if self.controller:
242
- res = self.controller.receive()
243
- else:
244
- raise ValueError("Controller is offline")
92
+ @abc.abstractmethod
93
+ def get_data_uv(
94
+ self, custom_path: str | None = None
95
+ ) -> Dict[int, AgilentHPLCChromatogram]:
96
+ pass
245
97
 
246
- if res.is_ok():
247
- self.send("Sleep 0.1")
248
- self.send("Print Rows")
249
- return res
250
- else:
251
- return Err("No rows could be read.")
98
+ @abc.abstractmethod
99
+ def get_report(
100
+ self, custom_path: str, report_type: ReportType = ReportType.TXT
101
+ ) -> List[AgilentReport]:
102
+ pass
252
103
 
253
104
  def check_hplc_is_running(self) -> bool:
254
105
  if self.controller:
@@ -334,28 +185,6 @@ class TableController(abc.ABC):
334
185
  return self.data_files[-1]
335
186
  return Err("Run did not complete as expected")
336
187
 
337
- @abc.abstractmethod
338
- def fuzzy_match_most_recent_folder(self, most_recent_folder: T) -> Result[T, str]:
339
- pass
340
-
341
- @abc.abstractmethod
342
- def get_data(
343
- self, custom_path: Optional[str] = None
344
- ) -> Union[List[AgilentChannelChromatogramData], AgilentChannelChromatogramData]:
345
- pass
346
-
347
- @abc.abstractmethod
348
- def get_data_uv(
349
- self, custom_path: str | None = None
350
- ) -> Dict[int, AgilentHPLCChromatogram]:
351
- pass
352
-
353
- @abc.abstractmethod
354
- def get_report(
355
- self, custom_path: str, report_type: ReportType = ReportType.TXT
356
- ) -> List[AgilentReport]:
357
- pass
358
-
359
188
  def get_uv_spectrum(self, path: str):
360
189
  data_uv = rb.agilent.chemstation.parse_file(os.path.join(path, "DAD1.UV"))
361
190
  times = data_uv.xlabels
@@ -0,0 +1,221 @@
1
+ """
2
+ Abstract module containing shared logic for Method and Sequence tables.
3
+
4
+ Authors: Lucy Hao
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import abc
10
+ import warnings
11
+ from typing import Optional, Union
12
+
13
+ from result import Err, Result
14
+
15
+ from ....control.controllers.comm import CommunicationController
16
+ from ....utils.macro import Command, Response
17
+ from ....utils.method_types import MethodDetails
18
+ from ....utils.sequence_types import SequenceTable
19
+ from ....utils.table_types import RegisterFlag, Table, TableOperation
20
+
21
+ TableType = Union[MethodDetails, SequenceTable]
22
+
23
+
24
+ class ABCTableController(abc.ABC):
25
+ def __init__(
26
+ self,
27
+ controller: Optional[CommunicationController],
28
+ table: Table,
29
+ ):
30
+ warnings.warn(
31
+ "This abstract class is not meant to be initialized. Use MethodController or SequenceController."
32
+ )
33
+ self.controller = controller
34
+ self.table_locator = table
35
+ self.table_state: Optional[TableType] = None
36
+
37
+ def receive(self) -> Result[Response, str]:
38
+ if self.controller:
39
+ for _ in range(10):
40
+ try:
41
+ return self.controller.receive()
42
+ except IndexError:
43
+ continue
44
+ return Err("Could not parse response")
45
+ else:
46
+ raise ValueError("Controller is offline!")
47
+
48
+ def send(self, cmd: Union[Command, str]):
49
+ if not self.controller:
50
+ raise RuntimeError(
51
+ "Communication controller must be initialized before sending command. It is currently in offline mode."
52
+ )
53
+ self.controller.send(cmd)
54
+
55
+ def sleepy_send(self, cmd: Union[Command, str]):
56
+ if self.controller:
57
+ self.controller.sleepy_send(cmd)
58
+ else:
59
+ raise ValueError("Controller is offline")
60
+
61
+ def sleep(self, seconds: int):
62
+ """
63
+ Tells the HPLC to wait for a specified number of seconds.
64
+
65
+ :param seconds: number of seconds to wait
66
+ """
67
+ self.send(Command.SLEEP_CMD.value.format(seconds=seconds))
68
+
69
+ def get_num(self, row: int, col_name: RegisterFlag) -> Union[int, float]:
70
+ if self.controller:
71
+ return self.controller.get_num_val(
72
+ TableOperation.GET_ROW_VAL.value.format(
73
+ register=self.table_locator.register,
74
+ table_name=self.table_locator.name,
75
+ row=row,
76
+ col_name=col_name.value,
77
+ )
78
+ )
79
+ else:
80
+ raise ValueError("Controller is offline")
81
+
82
+ def get_text(self, row: int, col_name: RegisterFlag) -> str:
83
+ if self.controller:
84
+ return self.controller.get_text_val(
85
+ TableOperation.GET_ROW_TEXT.value.format(
86
+ register=self.table_locator.register,
87
+ table_name=self.table_locator.name,
88
+ row=row,
89
+ col_name=col_name.value,
90
+ )
91
+ )
92
+ else:
93
+ raise ValueError("Controller is offline")
94
+
95
+ def add_new_col_num(self, col_name: RegisterFlag, val: Union[int, float]):
96
+ self.sleepy_send(
97
+ TableOperation.NEW_COL_VAL.value.format(
98
+ register=self.table_locator.register,
99
+ table_name=self.table_locator.name,
100
+ col_name=col_name,
101
+ val=val,
102
+ )
103
+ )
104
+
105
+ def add_new_col_text(self, col_name: RegisterFlag, val: str):
106
+ self.sleepy_send(
107
+ TableOperation.NEW_COL_TEXT.value.format(
108
+ register=self.table_locator.register,
109
+ table_name=self.table_locator.name,
110
+ col_name=col_name,
111
+ val=val,
112
+ )
113
+ )
114
+
115
+ def _edit_row_num(
116
+ self, col_name: RegisterFlag, val: Union[int, float], row: Optional[int] = None
117
+ ):
118
+ if row:
119
+ num_rows = self.get_num_rows()
120
+ if num_rows.is_ok():
121
+ if num_rows.value.num_response < row:
122
+ raise ValueError("Not enough rows to edit!")
123
+
124
+ self.sleepy_send(
125
+ TableOperation.EDIT_ROW_VAL.value.format(
126
+ register=self.table_locator.register,
127
+ table_name=self.table_locator.name,
128
+ row=row if row is not None else "Rows",
129
+ col_name=col_name,
130
+ val=val,
131
+ )
132
+ )
133
+
134
+ def _edit_row_text(
135
+ self, col_name: RegisterFlag, val: str, row: Optional[int] = None
136
+ ):
137
+ if row:
138
+ num_rows = self.get_num_rows()
139
+ if num_rows.is_ok():
140
+ if num_rows.value.num_response < row:
141
+ raise ValueError("Not enough rows to edit!")
142
+
143
+ self.sleepy_send(
144
+ TableOperation.EDIT_ROW_TEXT.value.format(
145
+ register=self.table_locator.register,
146
+ table_name=self.table_locator.name,
147
+ row=row if row is not None else "Rows",
148
+ col_name=col_name,
149
+ val=val,
150
+ )
151
+ )
152
+
153
+ @abc.abstractmethod
154
+ def get_row(self, row: int):
155
+ pass
156
+
157
+ def delete_row(self, row: int):
158
+ self.sleepy_send(
159
+ TableOperation.DELETE_ROW.value.format(
160
+ register=self.table_locator.register,
161
+ table_name=self.table_locator.name,
162
+ row=row,
163
+ )
164
+ )
165
+
166
+ def add_row(self):
167
+ """
168
+ Adds a row to the provided table for currently loaded method or sequence.
169
+ """
170
+ self.sleepy_send(
171
+ TableOperation.NEW_ROW.value.format(
172
+ register=self.table_locator.register, table_name=self.table_locator.name
173
+ )
174
+ )
175
+
176
+ def delete_table(self):
177
+ """
178
+ Deletes the table for the current loaded method or sequence.
179
+ """
180
+ self.sleepy_send(
181
+ TableOperation.DELETE_TABLE.value.format(
182
+ register=self.table_locator.register, table_name=self.table_locator.name
183
+ )
184
+ )
185
+
186
+ def new_table(self):
187
+ """
188
+ Creates the table for the currently loaded method or sequence.
189
+ """
190
+ self.send(
191
+ TableOperation.CREATE_TABLE.value.format(
192
+ register=self.table_locator.register, table_name=self.table_locator.name
193
+ )
194
+ )
195
+
196
+ def get_num_rows(self) -> Result[Response, str]:
197
+ self.send(
198
+ TableOperation.GET_NUM_ROWS.value.format(
199
+ register=self.table_locator.register,
200
+ table_name=self.table_locator.name,
201
+ col_name=RegisterFlag.NUM_ROWS,
202
+ )
203
+ )
204
+ self.send(
205
+ Command.GET_ROWS_CMD.value.format(
206
+ register=self.table_locator.register,
207
+ table_name=self.table_locator.name,
208
+ col_name=RegisterFlag.NUM_ROWS,
209
+ )
210
+ )
211
+ if self.controller:
212
+ res = self.controller.receive()
213
+ else:
214
+ raise ValueError("Controller is offline")
215
+
216
+ if res.is_ok():
217
+ self.send("Sleep 0.1")
218
+ self.send("Print Rows")
219
+ return res
220
+ else:
221
+ return Err("No rows could be read.")
@@ -0,0 +1,150 @@
1
+ """
2
+ Module to provide API for the communication with Agilent HPLC systems.
3
+
4
+ HPLCController sends commands to Chemstation software via a command file.
5
+ Answers are received via reply file. On the Chemstation side, a custom
6
+ Macro monitors the command file, executes commands and writes to the reply file.
7
+ Each command is given a number (cmd_no) to keep track of which commands have
8
+ been processed.
9
+
10
+ Authors: Alexander Hammer, Hessam Mehr, Lucy Hao
11
+ """
12
+
13
+ import time
14
+ from typing import Optional, Union
15
+
16
+ from result import Err, Ok, Result
17
+
18
+ from ...utils.macro import (
19
+ str_to_status,
20
+ HPLCErrorStatus,
21
+ Command,
22
+ Status,
23
+ )
24
+ from ...utils.mocking.abc_comm import ABCCommunicationController
25
+
26
+
27
+ class CommunicationController(ABCCommunicationController):
28
+ """
29
+ Class that communicates with Agilent using Macros
30
+ """
31
+
32
+ def __init__(
33
+ self,
34
+ comm_dir: str,
35
+ cmd_file: str = "cmd",
36
+ reply_file: str = "reply",
37
+ offline: bool = False,
38
+ debug: bool = False,
39
+ ):
40
+ """
41
+ :param comm_dir:
42
+ :param cmd_file: Name of command file
43
+ :param reply_file: Name of reply file
44
+ :param debug: whether to save log of sent commands
45
+ """
46
+ super().__init__(comm_dir, cmd_file, reply_file, offline, debug)
47
+
48
+ def get_num_val(self, cmd: str) -> Union[int, float]:
49
+ tries = 10
50
+ for _ in range(tries):
51
+ self.send(Command.GET_NUM_VAL_CMD.value.format(cmd=cmd))
52
+ res = self.receive()
53
+ if res.is_ok():
54
+ return res.ok_value.num_response
55
+ raise RuntimeError("Failed to get number.")
56
+
57
+ def get_text_val(self, cmd: str) -> str:
58
+ tries = 10
59
+ for _ in range(tries):
60
+ self.send(Command.GET_TEXT_VAL_CMD.value.format(cmd=cmd))
61
+ res = self.receive()
62
+ if res.is_ok():
63
+ return res.ok_value.string_response
64
+ raise RuntimeError("Failed to get string")
65
+
66
+ def get_status(self) -> Status:
67
+ """Get device status(es).
68
+
69
+ :return: list of ChemStation's current status
70
+ """
71
+ self.send(Command.GET_STATUS_CMD)
72
+ time.sleep(1)
73
+
74
+ try:
75
+ res = self.receive()
76
+ if res.is_err():
77
+ return HPLCErrorStatus.NORESPONSE
78
+ if res.is_ok():
79
+ parsed_response = self.receive().value.string_response
80
+ self._most_recent_hplc_status = str_to_status(parsed_response)
81
+ return self._most_recent_hplc_status
82
+ else:
83
+ raise RuntimeError("Failed to get status")
84
+ except IOError:
85
+ return HPLCErrorStatus.NORESPONSE
86
+ except IndexError:
87
+ return HPLCErrorStatus.MALFORMED
88
+
89
+ def _send(self, cmd: str, cmd_no: int, num_attempts=5) -> None:
90
+ """Low-level execution primitive. Sends a command string to HPLC.
91
+
92
+ :param cmd: string to be sent to HPLC
93
+ :param cmd_no: Command number
94
+ :param num_attempts: Number of attempts to send the command before raising exception.
95
+ :raises IOError: Could not write to command file.
96
+ """
97
+ err = None
98
+ for _ in range(num_attempts):
99
+ time.sleep(1)
100
+ try:
101
+ with open(self.cmd_file, "w", encoding="utf8") as cmd_file:
102
+ cmd_file.write(f"{cmd_no} {cmd}")
103
+ except IOError as e:
104
+ err = e
105
+ continue
106
+ else:
107
+ return
108
+ else:
109
+ raise IOError(f"Failed to send command #{cmd_no}: {cmd}.") from err
110
+
111
+ def _receive(self, cmd_no: int, num_attempts=100) -> Result[str, str]:
112
+ """Low-level execution primitive. Recives a response from HPLC.
113
+
114
+ :param cmd_no: Command number
115
+ :param num_attempts: Number of retries to open reply file
116
+ :raises IOError: Could not read reply file.
117
+ :return: Potential ChemStation response
118
+ """
119
+ err: Optional[Union[OSError, IndexError, ValueError]] = None
120
+ err_msg = ""
121
+ for _ in range(num_attempts):
122
+ time.sleep(1)
123
+
124
+ try:
125
+ with open(self.reply_file, "r", encoding="utf_16") as reply_file:
126
+ response = reply_file.read()
127
+ except OSError as e:
128
+ err = e
129
+ continue
130
+
131
+ try:
132
+ first_line = response.splitlines()[0]
133
+ try:
134
+ response_no = int(first_line.split()[0])
135
+ except ValueError as e:
136
+ err = e
137
+ err_msg = f"Caused by {first_line}"
138
+ except IndexError as e:
139
+ err = e
140
+ continue
141
+
142
+ # check that response corresponds to sent command
143
+ if response_no == cmd_no:
144
+ return Ok(response)
145
+ else:
146
+ continue
147
+ else:
148
+ return Err(
149
+ f"Failed to receive reply to command #{cmd_no} due to {err} caused by {err_msg}."
150
+ )