hutch-python 1.19.0__tar.gz → 1.20.0__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. {hutch_python-1.19.0 → hutch_python-1.20.0}/.gitignore +3 -0
  2. {hutch_python-1.19.0 → hutch_python-1.20.0}/PKG-INFO +1 -1
  3. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/releases.rst +17 -0
  4. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/_version.py +2 -2
  5. hutch_python-1.20.0/hutch_python/cli.py +236 -0
  6. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_cli.py +56 -2
  7. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python.egg-info/PKG-INFO +1 -1
  8. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python.egg-info/SOURCES.txt +0 -1
  9. hutch_python-1.19.0/docs/source/upcoming_release_notes/379-enh_limit_devices.rst +0 -22
  10. hutch_python-1.19.0/hutch_python/cli.py +0 -184
  11. {hutch_python-1.19.0 → hutch_python-1.20.0}/.coveragerc +0 -0
  12. {hutch_python-1.19.0 → hutch_python-1.20.0}/.flake8 +0 -0
  13. {hutch_python-1.19.0 → hutch_python-1.20.0}/.git_archival.txt +0 -0
  14. {hutch_python-1.19.0 → hutch_python-1.20.0}/.gitattributes +0 -0
  15. {hutch_python-1.19.0 → hutch_python-1.20.0}/.github/ISSUE_TEMPLATE.md +0 -0
  16. {hutch_python-1.19.0 → hutch_python-1.20.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  17. {hutch_python-1.19.0 → hutch_python-1.20.0}/.github/workflows/standard.yml +0 -0
  18. {hutch_python-1.19.0 → hutch_python-1.20.0}/.landscape.yml +0 -0
  19. {hutch_python-1.19.0 → hutch_python-1.20.0}/.pre-commit-config.yaml +0 -0
  20. {hutch_python-1.19.0 → hutch_python-1.20.0}/AUTHORS.rst +0 -0
  21. {hutch_python-1.19.0 → hutch_python-1.20.0}/CONTRIBUTING.rst +0 -0
  22. {hutch_python-1.19.0 → hutch_python-1.20.0}/LICENSE +0 -0
  23. {hutch_python-1.19.0 → hutch_python-1.20.0}/MANIFEST.in +0 -0
  24. {hutch_python-1.19.0 → hutch_python-1.20.0}/README.rst +0 -0
  25. {hutch_python-1.19.0 → hutch_python-1.20.0}/bin/hutch-python +0 -0
  26. {hutch_python-1.19.0 → hutch_python-1.20.0}/conda-recipe/meta.yaml +0 -0
  27. {hutch_python-1.19.0 → hutch_python-1.20.0}/dev-requirements.txt +0 -0
  28. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/Makefile +0 -0
  29. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/pre-release-notes.sh +0 -0
  30. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/release_notes.py +0 -0
  31. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/beamline.rst +0 -0
  32. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/bug.rst +0 -0
  33. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/cache.rst +0 -0
  34. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/cli.rst +0 -0
  35. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/conf.py +0 -0
  36. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/daq.rst +0 -0
  37. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/database.rst +0 -0
  38. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/debug.rst +0 -0
  39. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/environment.rst +0 -0
  40. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/experiment.rst +0 -0
  41. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/hutch_setup.rst +0 -0
  42. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/index.rst +0 -0
  43. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/ipython_log.rst +0 -0
  44. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/load_conf.rst +0 -0
  45. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/load_parts.rst +0 -0
  46. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/log_setup.rst +0 -0
  47. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/namespace.rst +0 -0
  48. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/object_configuration.rst +0 -0
  49. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/other_modules.rst +0 -0
  50. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/presets.rst +0 -0
  51. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/report.rst +0 -0
  52. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/start.rst +0 -0
  53. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/startup.rst +0 -0
  54. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/tips.rst +0 -0
  55. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/tutorial.ipynb +0 -0
  56. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/upcoming_release_notes/template-full.rst +0 -0
  57. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/upcoming_release_notes/template-short.rst +0 -0
  58. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/user_utils.rst +0 -0
  59. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/utils.rst +0 -0
  60. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs/source/yaml_files.rst +0 -0
  61. {hutch_python-1.19.0 → hutch_python-1.20.0}/docs-requirements.txt +0 -0
  62. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/__init__.py +0 -0
  63. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/__main__.py +0 -0
  64. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/bug.py +0 -0
  65. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/cache.py +0 -0
  66. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/calc_defaults.py +0 -0
  67. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/cam_load.py +0 -0
  68. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/constants.py +0 -0
  69. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/cookiecutter/cookiecutter.json +0 -0
  70. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/cookiecutter/{{ cookiecutter.hutch }}/.gitignore +0 -0
  71. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/cookiecutter/{{ cookiecutter.hutch }}/README.md +0 -0
  72. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/cookiecutter/{{ cookiecutter.hutch }}/conf.yml +0 -0
  73. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/cookiecutter/{{ cookiecutter.hutch }}/experiments/__init__.py +0 -0
  74. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/cookiecutter/{{ cookiecutter.hutch }}/set-dev +0 -0
  75. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/cookiecutter/{{ cookiecutter.hutch }}/{{ cookiecutter.hutch }}/__init__.py +0 -0
  76. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/cookiecutter/{{ cookiecutter.hutch }}/{{ cookiecutter.hutch }}/beamline.py +0 -0
  77. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/cookiecutter/{{ cookiecutter.hutch }}/{{ cookiecutter.hutch }}env +0 -0
  78. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/cookiecutter/{{ cookiecutter.hutch }}/{{ cookiecutter.hutch }}python +0 -0
  79. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/debug.py +0 -0
  80. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/env_version.py +0 -0
  81. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/epics_arch.py +0 -0
  82. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/exp_load.py +0 -0
  83. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/happi.py +0 -0
  84. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/ipython_log.py +0 -0
  85. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/lcls.py +0 -0
  86. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/load_conf.py +0 -0
  87. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/log_setup.py +0 -0
  88. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/logging.yml +0 -0
  89. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/mpl_config.py +0 -0
  90. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/namespace.py +0 -0
  91. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/obj_config.py +0 -0
  92. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/ophyd_settings.py +0 -0
  93. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/options.py +0 -0
  94. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/plan_defaults.py +0 -0
  95. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/plan_wrappers.py +0 -0
  96. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/print_hint_banner.py +0 -0
  97. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/pt_app_config.py +0 -0
  98. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/qs_load.py +0 -0
  99. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/sim.py +0 -0
  100. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/startup_script.py +0 -0
  101. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/templates/issue.template +0 -0
  102. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/__init__.py +0 -0
  103. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/bad_script.py +0 -0
  104. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/camviewer.cfg +0 -0
  105. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/conf.yaml +0 -0
  106. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/conftest.py +0 -0
  107. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/envs/pcds-1.0.0 +0 -0
  108. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/envs/pcds-2.0.0 +0 -0
  109. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/envs/z-env +0 -0
  110. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/experiments/sample_expname.py +0 -0
  111. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/experiments/x010.py +0 -0
  112. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/experiments/x011.py +0 -0
  113. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/happi_db.json +0 -0
  114. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/sample_module_1.py +0 -0
  115. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/sample_module_2.py +0 -0
  116. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/script.py +0 -0
  117. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_bug.py +0 -0
  118. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_cache.py +0 -0
  119. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_cam_load.py +0 -0
  120. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_epics_arch.py +0 -0
  121. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_experiment.py +0 -0
  122. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_happi.py +0 -0
  123. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_ipython_log.py +0 -0
  124. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_load_conf.py +0 -0
  125. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_log_setup.py +0 -0
  126. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_namespace.py +0 -0
  127. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_obj_config.py +0 -0
  128. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_plan_wrappers.py +0 -0
  129. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_questionnaire.py +0 -0
  130. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_tstpython.py +0 -0
  131. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_user_load.py +0 -0
  132. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/test_utils.py +0 -0
  133. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/tst/__init__.py +0 -0
  134. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/tst/beamline.py +0 -0
  135. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/tests/tstpython +0 -0
  136. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/user_load.py +0 -0
  137. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/utils.py +0 -0
  138. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python/version.py +0 -0
  139. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python.egg-info/dependency_links.txt +0 -0
  140. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python.egg-info/entry_points.txt +0 -0
  141. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python.egg-info/requires.txt +0 -0
  142. {hutch_python-1.19.0 → hutch_python-1.20.0}/hutch_python.egg-info/top_level.txt +0 -0
  143. {hutch_python-1.19.0 → hutch_python-1.20.0}/pyproject.toml +0 -0
  144. {hutch_python-1.19.0 → hutch_python-1.20.0}/requirements.txt +0 -0
  145. {hutch_python-1.19.0 → hutch_python-1.20.0}/setup.cfg +0 -0
@@ -118,3 +118,6 @@ hutch_python/tests/tst/db.txt
118
118
 
119
119
  # vscode
120
120
  .vscode
121
+
122
+ # unit test artifacts
123
+ *.sqlite
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hutch-python
3
- Version: 1.19.0
3
+ Version: 1.20.0
4
4
  Summary: Launcher and Config Reader for LCLS Interactive IPython Sessions
5
5
  Author: SLAC National Accelerator Laboratory
6
6
  License: Copyright (c) 2023, The Board of Trustees of the Leland Stanford Junior
@@ -2,6 +2,23 @@ Release History
2
2
  ###############
3
3
 
4
4
 
5
+ v1.20.0 (2024-04-19)
6
+ ====================
7
+
8
+ Features
9
+ --------
10
+ - Allow per-session separate ipython histories via ``--hist-file``
11
+ command-line argument. If omitted, default ipython behavior is used.
12
+ When ``--hist-file`` is included with no argument, the history file
13
+ will be written a local operator console hard drive, if available.
14
+ An argument can be provided to use any file as the history.sqlite file.
15
+
16
+ Contributors
17
+ ------------
18
+ - zllentz
19
+
20
+
21
+
5
22
  v1.19.0 (2024-04-15)
6
23
  ====================
7
24
 
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '1.19.0'
16
- __version_tuple__ = version_tuple = (1, 19, 0)
15
+ __version__ = version = '1.20.0'
16
+ __version_tuple__ = version_tuple = (1, 20, 0)
@@ -0,0 +1,236 @@
1
+ """
2
+ This module defines the command-line interface arguments for the
3
+ ``hutch-python`` script. It also provides utilities that are only used at
4
+ startup.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import argparse
9
+ import dataclasses
10
+ import logging
11
+ import os
12
+ import sys
13
+ from pathlib import Path
14
+ from string import Template
15
+
16
+ import IPython
17
+ import matplotlib
18
+ from cookiecutter.main import cookiecutter
19
+ from IPython import start_ipython
20
+ from traitlets.config import Config
21
+
22
+ from .constants import CONDA_BASE, DIR_MODULE
23
+ from .env_version import log_env
24
+ from .load_conf import load
25
+ from .log_setup import configure_log_directory, debug_mode, setup_logging
26
+
27
+ logger = logging.getLogger(__name__)
28
+ opts_cache = {}
29
+ DEFAULT_HISTFILE = "/u1/${USER}/hutch-python/history.sqlite"
30
+
31
+
32
+ # Define the parser
33
+ def get_parser() -> argparse.ArgumentParser:
34
+ parser = argparse.ArgumentParser(prog="hutch-python",
35
+ description="Launch LCLS Hutch Python")
36
+ parser.add_argument("--cfg", required=False, default=None,
37
+ help="Configuration yaml file")
38
+ parser.add_argument("--exp", required=False, default=None,
39
+ help="Experiment number override")
40
+ parser.add_argument("--debug", action="store_true", default=False,
41
+ help="Start in debug mode")
42
+ parser.add_argument("--sim", action="store_true", default=False,
43
+ help="Run with simulated DAQ (lcls1 only)")
44
+ parser.add_argument("--create", action="store", default=False,
45
+ help="Create a new hutch deployment")
46
+ parser.add_argument("--hist-file", nargs="?", action="store",
47
+ default=None, const=DEFAULT_HISTFILE,
48
+ help=(
49
+ "File to store the sqlite session history in. "
50
+ "${VARIABLES} will be substituted for "
51
+ "via shell environment variables, "
52
+ "Though in some cases these may be expanded by the shell "
53
+ "prior to reaching the python layer. "
54
+ "If omitted, defaults to the ipython default location. "
55
+ "If included but left blank, defaults to "
56
+ f"{DEFAULT_HISTFILE} "
57
+ "if the folder exists, "
58
+ "otherwise uses the ipython default location. "
59
+ "This folder is a local hard-drive location for lcls "
60
+ "operator consoles."
61
+ ))
62
+ parser.add_argument("script", nargs="?",
63
+ help="Run a script instead of running interactively")
64
+ return parser
65
+
66
+
67
+ parser = get_parser()
68
+
69
+ # Append to module docs
70
+ __doc__ += "\n::\n\n " + parser.format_help().replace("\n", "\n ")
71
+
72
+
73
+ @dataclasses.dataclass
74
+ class HutchPythonArgs:
75
+ cfg: str | None = None
76
+ exp: str | None = None
77
+ debug: bool = False
78
+ sim: bool = False
79
+ create: bool = False
80
+ hist_file: str | None = None
81
+ script: str | None = None
82
+
83
+
84
+ def configure_tab_completion(ipy_config):
85
+ """
86
+ Disable Jedi and tweak IPython tab completion.
87
+
88
+ Parameters
89
+ ----------
90
+ ipy_config : traitlets.config.Config
91
+ IPython configuration.
92
+ """
93
+ # Old API for disabling Jedi. Keep in just in case API changes back.
94
+ ipy_config.InteractiveShellApp.Completer.use_jedi = False
95
+ # New API for disabling Jedi (two access points documented, use both)
96
+ ipy_config.Completer.use_jedi = False
97
+ ipy_config.IPCompleter.use_jedi = False
98
+ try:
99
+ # Monkeypatch IPython completion - we need it to respect __dir__
100
+ # when Jedi is disabled.
101
+ # Details: https://github.com/pcdshub/pcdsdevices/issues/709
102
+ # First, access it to see that the internals have not changed:
103
+ IPython.core.completer.dir2
104
+ except AttributeError:
105
+ logger.debug("Looks like the IPython API changed!")
106
+ else:
107
+ # Then monkeypatch it in:
108
+ IPython.core.completer.dir2 = dir
109
+
110
+
111
+ def configure_ipython_session(args: HutchPythonArgs):
112
+ """
113
+ Configure a new IPython session.
114
+
115
+ Returns
116
+ -------
117
+ ipy_config : traitlets.config.Config
118
+ IPython configuration.
119
+ """
120
+ ipy_config = Config()
121
+ # Important Utilities
122
+ ipy_config.InteractiveShellApp.extensions = [
123
+ "hutch_python.ipython_log",
124
+ "hutch_python.bug",
125
+ "hutch_python.pt_app_config"
126
+ ]
127
+ # Matplotlib setup for ipython (automatically do %matplotlib)
128
+ backend = matplotlib.get_backend().replace("Agg", "").lower()
129
+ ipy_config.InteractiveShellApp.matplotlib = backend
130
+ if backend == "agg":
131
+ logger.warning("No matplotlib rendering available. "
132
+ "Methods that create plots will not "
133
+ "function properly.")
134
+
135
+ # Disable reformatting input with black
136
+ ipy_config.TerminalInteractiveShell.autoformatter = None
137
+ # Set up tab completion modifications
138
+ configure_tab_completion(ipy_config)
139
+
140
+ # disable default banner
141
+ ipy_config.TerminalIPythonApp.display_banner = False
142
+
143
+ # Run startup hook code, print banner after startup hook files
144
+ files = [
145
+ str(DIR_MODULE / "startup_script.py"),
146
+ str(DIR_MODULE / "print_hint_banner.py"),
147
+ ]
148
+ ipy_config.InteractiveShellApp.exec_files = files
149
+
150
+ # Custom history file with sensible non-NFS default for opr accounts
151
+ if args.hist_file is not None:
152
+ hist_file = Template(args.hist_file).safe_substitute(os.environ)
153
+ if hist_file == ":memory:" or Path(hist_file).parent.exists():
154
+ ipy_config.HistoryManager.hist_file = hist_file
155
+ else:
156
+ msg = f"No such directory for history file {hist_file}, using ipython default instead."
157
+ if args.hist_file == DEFAULT_HISTFILE:
158
+ # We expect this to be missing for non-opr users
159
+ logger.debug(msg)
160
+ else:
161
+ # You specified a file, so we need to warn about this
162
+ logger.warning(msg)
163
+
164
+ return ipy_config
165
+
166
+
167
+ def main():
168
+ """
169
+ Do the full hutch-python launch sequence.
170
+
171
+ Parses the user's cli arguments and distributes them as needed to the
172
+ setup functions.
173
+ """
174
+ # Parse the user's arguments
175
+ args = parser.parse_args(namespace=HutchPythonArgs())
176
+
177
+ # Set up logging first
178
+ if args.cfg is None:
179
+ log_dir = None
180
+ else:
181
+ log_dir = os.path.join(os.path.dirname(args.cfg), "logs")
182
+
183
+ configure_log_directory(log_dir)
184
+ setup_logging()
185
+
186
+ # Debug mode next
187
+ if args.debug:
188
+ debug_mode(True)
189
+
190
+ # Do the first log message, now that logging is ready
191
+ logger.debug("cli starting with args %s", args)
192
+
193
+ # Check and display the environment info as appropriate (very early)
194
+ log_env()
195
+
196
+ # Options that mean skipping the python environment
197
+ if args.create:
198
+ hutch = args.create
199
+ envs_dir = CONDA_BASE / "envs"
200
+ if envs_dir.exists():
201
+ # Pick most recent pcds release in our common env
202
+ base = str(CONDA_BASE)
203
+ path_obj = sorted(envs_dir.glob("pcds-*"))[-1]
204
+ env = path_obj.name
205
+ else:
206
+ # Fallback: pick current env
207
+ try:
208
+ base = str(Path(os.environ["CONDA_EXE"]).parent.parent)
209
+ env = os.environ["CONDA_DEFAULT_ENV"]
210
+ except KeyError:
211
+ # Take a stab at some non-conda defaults; ideally these would
212
+ # be configurable with argparse.
213
+ base = str(Path(sys.executable).parent)
214
+ env = hutch
215
+ logger.info(("Creating hutch-python dir for hutch %s using"
216
+ " base=%s env=%s"), hutch, base, env)
217
+ cookiecutter(str(DIR_MODULE / "cookiecutter"), no_input=True,
218
+ extra_context=dict(base=base, env=env, hutch=hutch))
219
+ return
220
+
221
+ # Save whether we are an interactive session or a script session
222
+ opts_cache["script"] = args.script
223
+
224
+ # Load objects based on the configuration file
225
+ objs = load(cfg=args.cfg, args=args)
226
+
227
+ script = opts_cache.get("script")
228
+ if script is None:
229
+ # Finally start the interactive session
230
+ start_ipython(argv=["--quick"], user_ns=objs,
231
+ config=configure_ipython_session(args))
232
+ else:
233
+ # Instead of setting up ipython, run the script with objs
234
+ with open(script) as fn:
235
+ code = compile(fn.read(), script, "exec")
236
+ exec(code, objs, objs)
@@ -1,14 +1,18 @@
1
1
  import logging
2
2
  import os
3
3
  import shutil
4
+ import subprocess
5
+ import sys
4
6
  from pathlib import Path
7
+ from string import Template
5
8
 
6
9
  import IPython.core.completer
7
10
  import pytest
8
11
  from conftest import cli_args, restore_logging
9
12
 
10
13
  import hutch_python.cli
11
- from hutch_python.cli import main
14
+ from hutch_python.cli import (HutchPythonArgs, configure_ipython_session,
15
+ get_parser, main)
12
16
  from hutch_python.load_conf import load
13
17
 
14
18
  from .conftest import skip_if_win32_generic
@@ -80,6 +84,56 @@ def test_create_arg():
80
84
  shutil.rmtree(test_dir)
81
85
 
82
86
 
87
+ def run_hpy_and_exit(*args: str) -> subprocess.CompletedProcess:
88
+ return subprocess.run(
89
+ [sys.executable, "-m", "hutch_python"] + list(args),
90
+ input="exit\n",
91
+ universal_newlines=True,
92
+ capture_output=True,
93
+ )
94
+
95
+
96
+ @pytest.mark.timeout(30)
97
+ def test_hist_file_arg(monkeypatch):
98
+ logger.debug("test_hist_file_arg")
99
+ test_hist_file = (CFG_PATH.parent / "history.sqlite").resolve()
100
+ bad_hist_file = (CFG_PATH.parent / "aesefiudh" / "history.sqlite").resolve()
101
+ memory_hist_filename = ":memory:"
102
+
103
+ # Test that the sqlite file gets made
104
+ # First, need to remove the file if it already exists
105
+ if test_hist_file.exists():
106
+ test_hist_file.unlink()
107
+
108
+ # Run with the good arg and exit
109
+ run_hpy_and_exit("--hist-file", str(test_hist_file))
110
+ # Was the history file created?
111
+ assert test_hist_file.exists()
112
+ # Remove the file for future tests
113
+ test_hist_file.unlink()
114
+ # With the bad hist file we should still run ok with just a warning
115
+ run_hpy_and_exit("--hist-file", str(bad_hist_file))
116
+ assert not test_hist_file.exists()
117
+ # Same with the in-memory choice
118
+ run_hpy_and_exit("--hist-file", memory_hist_filename)
119
+ assert not test_hist_file.exists()
120
+
121
+ # Exercise the template + check default usage
122
+ # We can't actually write to the default default in a test context
123
+ # But we can check what the config would be
124
+ new_default = str(test_hist_file.parent / "${USER}-history.sqlite")
125
+ new_default_filled = Template(new_default).substitute({"USER": os.environ["USER"]})
126
+ monkeypatch.setattr(
127
+ hutch_python.cli,
128
+ "DEFAULT_HISTFILE",
129
+ new_default,
130
+ )
131
+ parser = get_parser()
132
+ args = parser.parse_args(["--hist-file"], namespace=HutchPythonArgs())
133
+ ipy_config = configure_ipython_session(args)
134
+ assert ipy_config.HistoryManager.hist_file == new_default_filled
135
+
136
+
83
137
  @skip_if_win32_generic
84
138
  def test_run_script():
85
139
  logger.debug('test_run_script')
@@ -102,7 +156,7 @@ def test_ipython_tab_completion():
102
156
 
103
157
  # Side-effect of the following is monkey-patching `dir2` to "fix" this for
104
158
  # us.
105
- hutch_python.cli.configure_ipython_session()
159
+ hutch_python.cli.configure_ipython_session(HutchPythonArgs())
106
160
 
107
161
  completer = IPython.core.completer.Completer(namespace=ns)
108
162
  completer.limit_to__all__ = False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hutch-python
3
- Version: 1.19.0
3
+ Version: 1.20.0
4
4
  Summary: Launcher and Config Reader for LCLS Interactive IPython Sessions
5
5
  Author: SLAC National Accelerator Laboratory
6
6
  License: Copyright (c) 2023, The Board of Trustees of the Leland Stanford Junior
@@ -51,7 +51,6 @@ docs/source/tutorial.ipynb
51
51
  docs/source/user_utils.rst
52
52
  docs/source/utils.rst
53
53
  docs/source/yaml_files.rst
54
- docs/source/upcoming_release_notes/379-enh_limit_devices.rst
55
54
  docs/source/upcoming_release_notes/template-full.rst
56
55
  docs/source/upcoming_release_notes/template-short.rst
57
56
  hutch_python/__init__.py
@@ -1,22 +0,0 @@
1
- 379 enh_limit_devices
2
- #####################
3
-
4
- API Changes
5
- -----------
6
- - N/A
7
-
8
- Features
9
- --------
10
- - Adds load_level conf.yaml key for choosing the method used to gather happi devices
11
-
12
- Bugfixes
13
- --------
14
- - N/A
15
-
16
- Maintenance
17
- -----------
18
- - N/A
19
-
20
- Contributors
21
- ------------
22
- - tangkong
@@ -1,184 +0,0 @@
1
- """
2
- This module defines the command-line interface arguments for the
3
- ``hutch-python`` script. It also provides utilities that are only used at
4
- startup.
5
- """
6
- import argparse
7
- import logging
8
- import os
9
- import sys
10
- from pathlib import Path
11
-
12
- import IPython
13
- import matplotlib
14
- from cookiecutter.main import cookiecutter
15
- from IPython import start_ipython
16
- from traitlets.config import Config
17
-
18
- from .constants import CONDA_BASE, DIR_MODULE
19
- from .env_version import log_env
20
- from .load_conf import load
21
- from .log_setup import configure_log_directory, debug_mode, setup_logging
22
-
23
- logger = logging.getLogger(__name__)
24
- opts_cache = {}
25
-
26
- # Define the parser
27
- parser = argparse.ArgumentParser(prog='hutch-python',
28
- description='Launch LCLS Hutch Python')
29
- parser.add_argument('--cfg', required=False, default=None,
30
- help='Configuration yaml file')
31
- parser.add_argument('--exp', required=False, default=None,
32
- help='Experiment number override')
33
- parser.add_argument('--debug', action='store_true', default=False,
34
- help='Start in debug mode')
35
- parser.add_argument('--sim', action='store_true', default=False,
36
- help='Run with simulated DAQ (lcls1 only)')
37
- parser.add_argument('--create', action='store', default=False,
38
- help='Create a new hutch deployment')
39
- parser.add_argument('script', nargs='?',
40
- help='Run a script instead of running interactively')
41
-
42
- # Append to module docs
43
- __doc__ += '\n::\n\n ' + parser.format_help().replace('\n', '\n ')
44
-
45
-
46
- def configure_tab_completion(ipy_config):
47
- """
48
- Disable Jedi and tweak IPython tab completion.
49
-
50
- Parameters
51
- ----------
52
- ipy_config : traitlets.config.Config
53
- IPython configuration.
54
- """
55
- # Old API for disabling Jedi. Keep in just in case API changes back.
56
- ipy_config.InteractiveShellApp.Completer.use_jedi = False
57
- # New API for disabling Jedi (two access points documented, use both)
58
- ipy_config.Completer.use_jedi = False
59
- ipy_config.IPCompleter.use_jedi = False
60
- try:
61
- # Monkeypatch IPython completion - we need it to respect __dir__
62
- # when Jedi is disabled.
63
- # Details: https://github.com/pcdshub/pcdsdevices/issues/709
64
- # First, access it to see that the internals have not changed:
65
- IPython.core.completer.dir2
66
- except AttributeError:
67
- logger.debug('Looks like the IPython API changed!')
68
- else:
69
- # Then monkeypatch it in:
70
- IPython.core.completer.dir2 = dir
71
-
72
-
73
- def configure_ipython_session():
74
- """
75
- Configure a new IPython session.
76
-
77
- Returns
78
- -------
79
- ipy_config : traitlets.config.Config
80
- IPython configuration.
81
- """
82
- ipy_config = Config()
83
- # Important Utilities
84
- ipy_config.InteractiveShellApp.extensions = [
85
- 'hutch_python.ipython_log',
86
- 'hutch_python.bug',
87
- 'hutch_python.pt_app_config'
88
- ]
89
- # Matplotlib setup for ipython (automatically do %matplotlib)
90
- backend = matplotlib.get_backend().replace('Agg', '').lower()
91
- ipy_config.InteractiveShellApp.matplotlib = backend
92
- if backend == 'agg':
93
- logger.warning('No matplotlib rendering available. '
94
- 'Methods that create plots will not '
95
- 'function properly.')
96
-
97
- # Disable reformatting input with black
98
- ipy_config.TerminalInteractiveShell.autoformatter = None
99
- # Set up tab completion modifications
100
- configure_tab_completion(ipy_config)
101
-
102
- # disable default banner
103
- ipy_config.TerminalIPythonApp.display_banner = False
104
-
105
- # Run startup hook code, print banner after startup hook files
106
- files = [
107
- str(DIR_MODULE / "startup_script.py"),
108
- str(DIR_MODULE / "print_hint_banner.py"),
109
- ]
110
- ipy_config.InteractiveShellApp.exec_files = files
111
-
112
- return ipy_config
113
-
114
-
115
- def main():
116
- """
117
- Do the full hutch-python launch sequence.
118
-
119
- Parses the user's cli arguments and distributes them as needed to the
120
- setup functions.
121
- """
122
- # Parse the user's arguments
123
- args = parser.parse_args()
124
-
125
- # Set up logging first
126
- if args.cfg is None:
127
- log_dir = None
128
- else:
129
- log_dir = os.path.join(os.path.dirname(args.cfg), 'logs')
130
-
131
- configure_log_directory(log_dir)
132
- setup_logging()
133
-
134
- # Debug mode next
135
- if args.debug:
136
- debug_mode(True)
137
-
138
- # Do the first log message, now that logging is ready
139
- logger.debug('cli starting with args %s', args)
140
-
141
- # Check and display the environment info as appropriate (very early)
142
- log_env()
143
-
144
- # Options that mean skipping the python environment
145
- if args.create:
146
- hutch = args.create
147
- envs_dir = CONDA_BASE / 'envs'
148
- if envs_dir.exists():
149
- # Pick most recent pcds release in our common env
150
- base = str(CONDA_BASE)
151
- path_obj = sorted(envs_dir.glob('pcds-*'))[-1]
152
- env = path_obj.name
153
- else:
154
- # Fallback: pick current env
155
- try:
156
- base = str(Path(os.environ['CONDA_EXE']).parent.parent)
157
- env = os.environ['CONDA_DEFAULT_ENV']
158
- except KeyError:
159
- # Take a stab at some non-conda defaults; ideally these would
160
- # be configurable with argparse.
161
- base = str(Path(sys.executable).parent)
162
- env = hutch
163
- logger.info(('Creating hutch-python dir for hutch %s using'
164
- ' base=%s env=%s'), hutch, base, env)
165
- cookiecutter(str(DIR_MODULE / 'cookiecutter'), no_input=True,
166
- extra_context=dict(base=base, env=env, hutch=hutch))
167
- return
168
-
169
- # Save whether we are an interactive session or a script session
170
- opts_cache['script'] = args.script
171
-
172
- # Load objects based on the configuration file
173
- objs = load(cfg=args.cfg, args=args)
174
-
175
- script = opts_cache.get('script')
176
- if script is None:
177
- # Finally start the interactive session
178
- start_ipython(argv=['--quick'], user_ns=objs,
179
- config=configure_ipython_session())
180
- else:
181
- # Instead of setting up ipython, run the script with objs
182
- with open(script) as fn:
183
- code = compile(fn.read(), script, 'exec')
184
- exec(code, objs, objs)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes